From a790073eff19700677ab4435fb8b6118533bbbab Mon Sep 17 00:00:00 2001 From: Alexandre Takeshi Date: Thu, 25 May 2023 18:18:36 -0300 Subject: [PATCH 1/9] Share buttons e meta tags implementados --- src/main/webapp/WEB-INF/tags/template.tag | 15 ++++++++++++++- .../WEB-INF/view/client/details-request.jsp | 5 ++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/main/webapp/WEB-INF/tags/template.tag b/src/main/webapp/WEB-INF/tags/template.tag index 596f5f45..5221be50 100644 --- a/src/main/webapp/WEB-INF/tags/template.tag +++ b/src/main/webapp/WEB-INF/tags/template.tag @@ -13,6 +13,18 @@ + + + + + + + + + + + + ${title} @@ -20,6 +32,8 @@ + + @@ -88,6 +102,5 @@ this.location = "#" + objID; } - diff --git a/src/main/webapp/WEB-INF/view/client/details-request.jsp b/src/main/webapp/WEB-INF/view/client/details-request.jsp index 1ff13419..5c69f70f 100644 --- a/src/main/webapp/WEB-INF/view/client/details-request.jsp +++ b/src/main/webapp/WEB-INF/view/client/details-request.jsp @@ -28,7 +28,7 @@

Escolha um ${expertise.name}!

-
+

${jobRequest.description}

Pedido expedido em ${jobRequest.dateTarget}

@@ -272,7 +272,6 @@ }); } }); - - }); + From 73fb9eea0c398ac09b2c1f534bd9b92a7d357e21 Mon Sep 17 00:00:00 2001 From: taisHryssai Date: Tue, 15 Aug 2023 21:09:24 -0300 Subject: [PATCH 2/9] =?UTF-8?q?Adicionar=20an=C3=BAncios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/MyAdsController.java | 87 +++++++++ .../model/entity/DurationService.java | 23 +++ .../servicebook/model/entity/PriceUnit.java | 23 +++ src/main/resources/data.sql | 21 ++- .../view/professional/my-ads-register.jsp | 178 ++++++++++++++++++ .../WEB-INF/view/professional/my-ads.jsp | 107 +++++++++++ .../resources/styles/professional/ads.css | 10 + 7 files changed, 446 insertions(+), 3 deletions(-) create mode 100644 src/main/java/br/edu/utfpr/servicebook/controller/MyAdsController.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/entity/DurationService.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/entity/PriceUnit.java create mode 100644 src/main/webapp/WEB-INF/view/professional/my-ads-register.jsp create mode 100644 src/main/webapp/WEB-INF/view/professional/my-ads.jsp create mode 100644 src/main/webapp/assets/resources/styles/professional/ads.css diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/MyAdsController.java b/src/main/java/br/edu/utfpr/servicebook/controller/MyAdsController.java new file mode 100644 index 00000000..e21964d6 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/controller/MyAdsController.java @@ -0,0 +1,87 @@ +package br.edu.utfpr.servicebook.controller; + +import br.edu.utfpr.servicebook.model.dto.ExpertiseDTO; +import br.edu.utfpr.servicebook.model.dto.IndividualDTO; +import br.edu.utfpr.servicebook.model.dto.JobContractedDTO; +import br.edu.utfpr.servicebook.model.dto.ServiceDTO; +import br.edu.utfpr.servicebook.model.entity.*; +import br.edu.utfpr.servicebook.model.mapper.ExpertiseMapper; +import br.edu.utfpr.servicebook.model.mapper.ServiceMapper; +import br.edu.utfpr.servicebook.service.ExpertiseService; +import br.edu.utfpr.servicebook.service.ServiceService; +import br.edu.utfpr.servicebook.util.pagination.PaginationUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; + +import javax.annotation.security.PermitAll; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +@RequestMapping("/minha-conta/profissional/meus-anuncios") +@Controller +public class MyAdsController { + public static final Logger log = LoggerFactory.getLogger(ProfessionalHomeController.class); + + @Autowired + private ServiceService serviceService; + + @Autowired + private ServiceMapper serviceMapper; + + @Autowired + private ExpertiseService expertiseService; + + @Autowired + private ExpertiseMapper expertiseMapper; + + @GetMapping + @PermitAll + protected ModelAndView showMyAds() throws Exception { + ModelAndView mv = new ModelAndView("professional/my-ads"); + + //paginação de serviços + PageRequest pageRequest = PageRequest.of(0, 5); + Page servicePage = serviceService.findAll(pageRequest); + List serviceDTOS = servicePage.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); + + mv.addObject("services", serviceDTOS); + + return mv; + } + + @GetMapping("/novo") + @PermitAll + protected ModelAndView registerMyAds() throws Exception { + ModelAndView mv = new ModelAndView("professional/my-ads-register"); + + //paginação de serviços + PageRequest pageRequest = PageRequest.of(0, 5); + + List expertises = expertiseService.findAll(); + List expertiseDTOs = expertises.stream() + .map(s -> expertiseMapper.toDto(s)) + .collect(Collectors.toList()); + mv.addObject("expertises", expertiseDTOs); + + Page servicePage = serviceService.findAll(pageRequest); + List serviceDTOS = servicePage.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); + mv.addObject("services", serviceDTOS); + + + return mv; + } +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/DurationService.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/DurationService.java new file mode 100644 index 00000000..6baf0682 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/DurationService.java @@ -0,0 +1,23 @@ +package br.edu.utfpr.servicebook.model.entity; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@RequiredArgsConstructor +@Table(name = "duration_services") +@Entity +public class DurationService { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NonNull + @Column(unique = true) + private String name; +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/PriceUnit.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/PriceUnit.java new file mode 100644 index 00000000..68950fc4 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/PriceUnit.java @@ -0,0 +1,23 @@ +package br.edu.utfpr.servicebook.model.entity; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +import javax.persistence.*; + +@Data +@NoArgsConstructor +@RequiredArgsConstructor +@Table(name = "price_units") +@Entity +public class PriceUnit { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NonNull + @Column(unique = true) + private String name; +} diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 82ffd9c3..899bf343 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -154,6 +154,21 @@ VALUES ('1', '2', 'false'), INSERT INTO follows (client_id, professional_id) -VALUES (4, 2) - - +VALUES (4, 2); + +-- DURAÇÃO DE SERVIÇOS +INSERT INTO duration_services (name) +VALUES ('Sem agendamento'), + ('30 minutos'), + ('1 hora'), + ('1 hora e meia'), + ('2 horas'), + ('3 horas'), + ('Um período do dia'), + ('O dia inteiro'); + +-- UNIDADE DE PREÇO +INSERT INTO price_units (name) +VALUES ('Hora'), + ('Metro quadrado'), + ('Unidade'); diff --git a/src/main/webapp/WEB-INF/view/professional/my-ads-register.jsp b/src/main/webapp/WEB-INF/view/professional/my-ads-register.jsp new file mode 100644 index 00000000..68127361 --- /dev/null +++ b/src/main/webapp/WEB-INF/view/professional/my-ads-register.jsp @@ -0,0 +1,178 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +
+
+
+
+ + + +
+

Anúnciar Serviço

+
+
+

+ Serviço Individual, você adiciona um anúncio simples, podendo alterar o titulo do anúncio caso ache necessário. +

+

+ Combinação de Serviços, você pode adicionar mais de um serviço no anúncio, desde que todos estejam ativados para anúncio, + como por exemplo balanceamento + geometria . +

+

+ Pacote de Serviços, você pode adicionar uma quantidade do mesmo produto, como por exemplo 5 sessões de massagens . +

+
+ +
+
+ +
+
+

Qual o tipo do serviço?

+ +
+ +
+ +<%--
--%> +<%--

Qual a especialidade?

--%> +<%-- --%> +<%--
--%> + +
+

Qual o serviço?

+ +
+ +
+

Titulo

+ +

+ +

+ +
+ +
+

Qual a unidade de preço do serviço/

+ +
+ +
+

Quanto você cobra por este serviço?

+ +
+ + + +
+

Qual a Duração do serviço?

+ +
+ +
+ +
+
+ +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/professional/my-ads.jsp b/src/main/webapp/WEB-INF/view/professional/my-ads.jsp new file mode 100644 index 00000000..88a753c0 --- /dev/null +++ b/src/main/webapp/WEB-INF/view/professional/my-ads.jsp @@ -0,0 +1,107 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + +
+
+
+
+ + + +
+

Meus Anúncios

+
+
+

Adicione anúncios dos serviços que você oferece dentro do Servicebook.

+

Se ativado o agendamento, o cliente possuira acesso a sua agenda, podendo visualizar os dias e horários + disponíveis. Além disso, você pode adicioanar o preço e duração dos seus serviços, dessa forma + permitindo que clientes adquiram seus serviços de forma rápida.

+
+ +
+ +
+ + + + +
+
+
+
+ + + + + +
+
+ + \ No newline at end of file diff --git a/src/main/webapp/assets/resources/styles/professional/ads.css b/src/main/webapp/assets/resources/styles/professional/ads.css new file mode 100644 index 00000000..fdd5ec69 --- /dev/null +++ b/src/main/webapp/assets/resources/styles/professional/ads.css @@ -0,0 +1,10 @@ +.active-profission{ + border: #00b0ff 2px solid; + padding: 20px; +} +/*LABEL DOS CAMPOS*/ +.label-ads{ + /*margin-top: 5% !important;*/ + margin: 0 !important; + font-size: .75rem !important; +} \ No newline at end of file From 6dff0fe7fa7fd62ec3abb823cec6e08b63c133b3 Mon Sep 17 00:00:00 2001 From: taisHryssai Date: Wed, 11 Oct 2023 00:01:40 -0300 Subject: [PATCH 3/9] =?UTF-8?q?P=C3=A1gina=20para=20adicionar=20an=C3=BAnc?= =?UTF-8?q?ios=20do=20profissional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/MyAdsController.java | 223 +++++++++++++++++- .../dto/ProfessionalServiceOfferingDTO.java | 21 ++ ...ProfessionalServicePackageOfferingDTO.java | 65 +++++ .../entity/ProfessionalServiceOffering.java | 23 ++ .../ProfessionalServiceOfferingAdItemPK.java | 1 + .../ProfessionalServicePackageOffering.java | 24 ++ ...sionalServiceOfferingAdItemRepository.java | 21 +- ...ProfessionalServiceOfferingRepository.java | 20 ++ ...ionalServicePackageOfferingRepository.java | 5 +- ...fessionalServiceOfferingAdItemService.java | 14 ++ .../ProfessionalServiceOfferingService.java | 26 ++ ...essionalServicePackageOfferingService.java | 20 +- src/main/resources/data.sql | 16 +- .../webapp/WEB-INF/tags/my-ads-combined.tag | 37 +++ .../webapp/WEB-INF/tags/my-ads-package.tag | 35 +++ .../WEB-INF/tags/navbar-professional.tag | 1 + .../professional/ads/my-ads-combineds.jsp | 97 ++++++++ .../professional/ads/my-ads-individuals.jsp | 97 ++++++++ .../view/professional/ads/my-ads-packages.jsp | 97 ++++++++ .../professional/my-ads-register-combined.jsp | 80 +++++++ .../professional/my-ads-register-package.jsp | 84 +++++++ .../view/professional/my-ads-register.jsp | 129 ++++------ .../WEB-INF/view/professional/my-ads.jsp | 167 +++++++------ .../webapp/assets/resources/scripts/main.js | 184 ++++++++++++++- .../resources/styles/professional/ads.css | 28 ++- 25 files changed, 1338 insertions(+), 177 deletions(-) create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServicePackageOfferingDTO.java create mode 100644 src/main/webapp/WEB-INF/tags/my-ads-combined.tag create mode 100644 src/main/webapp/WEB-INF/tags/my-ads-package.tag create mode 100644 src/main/webapp/WEB-INF/view/professional/ads/my-ads-combineds.jsp create mode 100644 src/main/webapp/WEB-INF/view/professional/ads/my-ads-individuals.jsp create mode 100644 src/main/webapp/WEB-INF/view/professional/ads/my-ads-packages.jsp create mode 100644 src/main/webapp/WEB-INF/view/professional/my-ads-register-combined.jsp create mode 100644 src/main/webapp/WEB-INF/view/professional/my-ads-register-package.jsp diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/MyAdsController.java b/src/main/java/br/edu/utfpr/servicebook/controller/MyAdsController.java index e21964d6..8e28c97c 100644 --- a/src/main/java/br/edu/utfpr/servicebook/controller/MyAdsController.java +++ b/src/main/java/br/edu/utfpr/servicebook/controller/MyAdsController.java @@ -1,32 +1,27 @@ package br.edu.utfpr.servicebook.controller; -import br.edu.utfpr.servicebook.model.dto.ExpertiseDTO; -import br.edu.utfpr.servicebook.model.dto.IndividualDTO; -import br.edu.utfpr.servicebook.model.dto.JobContractedDTO; -import br.edu.utfpr.servicebook.model.dto.ServiceDTO; +import br.edu.utfpr.servicebook.model.dto.*; import br.edu.utfpr.servicebook.model.entity.*; import br.edu.utfpr.servicebook.model.mapper.ExpertiseMapper; import br.edu.utfpr.servicebook.model.mapper.ServiceMapper; -import br.edu.utfpr.servicebook.service.ExpertiseService; -import br.edu.utfpr.servicebook.service.ServiceService; -import br.edu.utfpr.servicebook.util.pagination.PaginationUtil; +import br.edu.utfpr.servicebook.security.IAuthentication; +import br.edu.utfpr.servicebook.service.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; - +import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.annotation.security.PermitAll; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; - @RequestMapping("/minha-conta/profissional/meus-anuncios") @Controller public class MyAdsController { @@ -44,10 +39,26 @@ public class MyAdsController { @Autowired private ExpertiseMapper expertiseMapper; + @Autowired + private ProfessionalServiceOfferingService professionalServiceOfferingService; + + @Autowired + private UserService userService; + + @Autowired + private IAuthentication authentication; + + @Autowired + private ProfessionalServicePackageOfferingService professionalServicePackageOfferingService; + + @Autowired + private ProfessionalServiceOfferingAdItemService professionalServiceOfferingAdItemService; + @GetMapping @PermitAll protected ModelAndView showMyAds() throws Exception { ModelAndView mv = new ModelAndView("professional/my-ads"); + Optional oUser = (userService.findByEmail(authentication.getEmail())); //paginação de serviços PageRequest pageRequest = PageRequest.of(0, 5); @@ -56,8 +67,17 @@ protected ModelAndView showMyAds() throws Exception { .map(s -> serviceMapper.toDto(s)) .collect(Collectors.toList()); - mv.addObject("services", serviceDTOS); + List professionalServiceOfferings = professionalServiceOfferingService.findProfessionalServiceOfferingByUser(oUser.get()); + List servicesIndividuals = professionalServiceOfferingService.findFirst3ProfessionalServiceOfferingByUserAndType(oUser.get(), ProfessionalServiceOffering.Type.INDIVIDUAL); + + List servicesPackages = professionalServicePackageOfferingService.findAllByUserAndType(oUser.get(), ProfessionalServicePackageOffering.Type.SIMPLE_PACKAGE); + List servicesCombined = professionalServicePackageOfferingService.findByTypeAndUser(oUser.get(), ProfessionalServicePackageOffering.Type.COMBINED_PACKAGE); + mv.addObject("services", serviceDTOS); + mv.addObject("professionalServiceOfferings", professionalServiceOfferings); + mv.addObject("servicesIndividuals", servicesIndividuals); + mv.addObject("servicesPackages", servicesPackages); + mv.addObject("servicesCombined", servicesCombined); return mv; } @@ -84,4 +104,181 @@ protected ModelAndView registerMyAds() throws Exception { return mv; } -} + + /** + * Adiciona um serviço individual. + * @param professionalServiceOfferingDTO + * @param errors + * @param redirectAttributes + * @return + * @throws Exception + */ + @PostMapping("/novo/individual") + @PermitAll + public String saveAds(ProfessionalServiceOfferingDTO professionalServiceOfferingDTO, BindingResult errors, RedirectAttributes + redirectAttributes) throws Exception { + Optional oUser = (userService.findByEmail(authentication.getEmail())); + + ModelAndView mv = new ModelAndView("professional/my-ads-register"); + + ProfessionalServiceOffering professionalServiceOffering = new ProfessionalServiceOffering(); + Optional oService = serviceService.findById(professionalServiceOfferingDTO.getServiceId()); + professionalServiceOffering.setUser(oUser.get()); + professionalServiceOffering.setPrice(professionalServiceOfferingDTO.getPrice()); + professionalServiceOffering.setUnit(professionalServiceOfferingDTO.getUnit()); + professionalServiceOffering.setDuration(professionalServiceOfferingDTO.getDuration()); + professionalServiceOffering.setType(ProfessionalServiceOffering.Type.INDIVIDUAL); + + professionalServiceOffering.setDescription(professionalServiceOfferingDTO.getDescription()); + if(oService.isPresent()){ + professionalServiceOffering.setService(oService.get()); + } + + //grava o nome do serviço original + professionalServiceOffering.setName(oService.get().getName()); + professionalServiceOfferingService.save(professionalServiceOffering); + + return("redirect:/minha-conta/profissional/meus-anuncios"); + } + + /** + * Adiciona um pacote de serviço. + * @param professionalServicePackageOfferingDTO + * @param professionalServiceOfferingDTO + * @return + * @throws Exception + */ + @PostMapping("/novo/pacote") + @PermitAll + public String saveAdsPackage(ProfessionalServiceOfferingDTO professionalServiceOfferingDTO, ProfessionalServicePackageOfferingDTO professionalServicePackageOfferingDTO, BindingResult errors, RedirectAttributes + redirectAttributes) throws Exception { + Optional oUser = (userService.findByEmail(authentication.getEmail())); + ModelAndView mv = new ModelAndView("professional/my-ads-register"); + + Optional oService = serviceService.findById(professionalServicePackageOfferingDTO.getServiceId()); + + ProfessionalServicePackageOffering professionalServicePackageOffering = new ProfessionalServicePackageOffering(); + professionalServicePackageOffering.setPrice(professionalServicePackageOfferingDTO.getPrice()); + professionalServicePackageOffering.setType(ProfessionalServicePackageOffering.Type.SIMPLE_PACKAGE); + professionalServicePackageOffering.setUnit(professionalServicePackageOfferingDTO.getUnit()); + professionalServicePackageOffering.setDuration(professionalServicePackageOfferingDTO.getDuration()); + professionalServicePackageOffering.setDescription(professionalServicePackageOfferingDTO.getDescription()); + //grava o nome do serviço original + professionalServicePackageOffering.setName(oService.get().getName()); + professionalServicePackageOffering.setAmount(professionalServicePackageOfferingDTO.getAmount()); + professionalServicePackageOffering.setUser(oUser.get()); + professionalServicePackageOffering.setService(oService.get()); + + professionalServicePackageOfferingService.save(professionalServicePackageOffering); + + return("redirect:/minha-conta/profissional/meus-anuncios"); + } + /** + * Adiciona um serviço combinado com um ou mais serviços. + * @param professionalServicePackageOfferingDTO + * @param professionalServiceOfferingDTO + * @return + * @throws Exception + */ + @PostMapping("/novo/combinado") + @PermitAll + public String saveAdsCombined(ProfessionalServiceOfferingDTO professionalServiceOfferingDTO, ProfessionalServicePackageOfferingDTO professionalServicePackageOfferingDTO, BindingResult errors, RedirectAttributes + redirectAttributes) throws Exception { + Optional oUser = (userService.findByEmail(authentication.getEmail())); + + ModelAndView mv = new ModelAndView("professional/my-ads-register"); + ProfessionalServicePackageOffering professionalServicePackageOffering = new ProfessionalServicePackageOffering(); + professionalServicePackageOffering.setPrice(professionalServicePackageOfferingDTO.getPrice()); + professionalServicePackageOffering.setType(ProfessionalServicePackageOffering.Type.COMBINED_PACKAGE); + professionalServicePackageOffering.setUnit(professionalServicePackageOfferingDTO.getUnit()); + professionalServicePackageOffering.setDuration(professionalServicePackageOfferingDTO.getDuration()); + professionalServicePackageOffering.setDescription(professionalServicePackageOfferingDTO.getDescription()); + professionalServicePackageOffering.setName(professionalServicePackageOfferingDTO.getDescription()); + + //grava o nome do serviço original + professionalServicePackageOffering.setUser(oUser.get()); + + professionalServicePackageOfferingService.save(professionalServicePackageOffering); + + for (Long valor : professionalServiceOfferingDTO.getDescriptions()) { + ProfessionalServiceOffering professionalServiceOffering = new ProfessionalServiceOffering(); + Optional oService = serviceService.findById(valor); + + professionalServiceOffering.setDescription(professionalServicePackageOfferingDTO.getDescription()); + //grava o nome do serviço original + professionalServiceOffering.setName(oService.get().getName()); + professionalServiceOffering.setType(ProfessionalServiceOffering.Type.COMBINED_PACKAGE); + professionalServiceOffering.setUnit(professionalServiceOfferingDTO.getUnit()); + professionalServiceOffering.setDuration(professionalServiceOfferingDTO.getDuration()); + professionalServiceOffering.setPrice(professionalServiceOfferingDTO.getPrice()); + professionalServiceOffering.setUser(oUser.get()); + professionalServiceOffering.setService(oService.get()); + professionalServiceOfferingService.save(professionalServiceOffering); +// +// ProfessionalServiceOfferingAdItem professionalServiceOfferingAdItem = new ProfessionalServiceOfferingAdItem(professionalServiceOffering, professionalServicePackageOffering); +// professionalServiceOfferingAdItem.setAmount(professionalServicePackageOfferingDTO.getAmount()); +// professionalServiceOfferingAdItemService.save(professionalServiceOfferingAdItem); + } + + return("redirect:/minha-conta/profissional/meus-anuncios"); + } + @GetMapping("/pacotes") + @PermitAll + protected ModelAndView showMyAdsPackages() throws Exception { + ModelAndView mv = new ModelAndView("professional/ads/my-ads-packages"); + Optional oUser = (userService.findByEmail(authentication.getEmail())); + + //paginação de serviços + PageRequest pageRequest = PageRequest.of(0, 5); + Page servicePage = serviceService.findAll(pageRequest); + List serviceDTOS = servicePage.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); + + List servicesPackages = professionalServicePackageOfferingService.findByTypeAndUser(oUser.get(), ProfessionalServicePackageOffering.Type.SIMPLE_PACKAGE); + + mv.addObject("services", serviceDTOS); + mv.addObject("servicesPackages", servicesPackages); + return mv; + } + + @GetMapping("/individuais") + @PermitAll + protected ModelAndView showMyAdsIndividuals() throws Exception { + ModelAndView mv = new ModelAndView("professional/ads/my-ads-individuals"); + Optional oUser = (userService.findByEmail(authentication.getEmail())); + + //paginação de serviços + PageRequest pageRequest = PageRequest.of(0, 5); + Page servicePage = serviceService.findAll(pageRequest); + List serviceDTOS = servicePage.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); + + List professionalServiceOfferings = professionalServiceOfferingService.findProfessionalServiceOfferingByUserAndType(oUser.get(), ProfessionalServiceOffering.Type.INDIVIDUAL); + + mv.addObject("services", serviceDTOS); + mv.addObject("professionalServiceOfferings", professionalServiceOfferings); + return mv; + } + + @GetMapping("/combinados") + @PermitAll + protected ModelAndView showMyAdsCombineds() throws Exception { + ModelAndView mv = new ModelAndView("professional/ads/my-ads-combineds"); + Optional oUser = (userService.findByEmail(authentication.getEmail())); + + //paginação de serviços + PageRequest pageRequest = PageRequest.of(0, 5); + Page servicePage = serviceService.findAll(pageRequest); + List serviceDTOS = servicePage.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); + + List servicesCombined = professionalServicePackageOfferingService.findByTypeAndUser(oUser.get(), ProfessionalServicePackageOffering.Type.COMBINED_PACKAGE); + + mv.addObject("services", serviceDTOS); + mv.addObject("servicesCombined", servicesCombined); + return mv; + } +} \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServiceOfferingDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServiceOfferingDTO.java index 01c3d995..9dfa354f 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServiceOfferingDTO.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServiceOfferingDTO.java @@ -1,11 +1,13 @@ package br.edu.utfpr.servicebook.model.dto; +import br.edu.utfpr.servicebook.model.entity.ProfessionalServicePackageOffering; import br.edu.utfpr.servicebook.model.entity.Service; import br.edu.utfpr.servicebook.model.entity.User; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.*; +import java.util.Set; /** * Classe que representa um serviço adicionado por um profissional ao seu portfólio. @@ -19,6 +21,13 @@ public class ProfessionalServiceOfferingDTO { private Long id; + public enum Type { + INDIVIDUAL, + COMBINED_PACKAGE, + SIMPLE_PACKAGE + } + + private Type type; /** * Nome do serviço. * O profissional pode customizar o nome do serviço cadastrado pelo administrador de várias maneiras, dependendo @@ -34,6 +43,17 @@ public class ProfessionalServiceOfferingDTO { * Caso ele não especifique a descrição do serviço, a descrição do serviço cadastrado pelo administrador será usada. */ private String description; + private Set descriptions; + + /** + * Unidade de preço do serviço. + */ + private String unit; + + /** + * Duração do serviço. + */ + private String duration; /** * Serviço cadastrado pelo administrador. @@ -43,6 +63,7 @@ public class ProfessionalServiceOfferingDTO { private ServiceDTO service; private Long serviceId; + private Long price; /** * Profissional que oferece o serviço. diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServicePackageOfferingDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServicePackageOfferingDTO.java new file mode 100644 index 00000000..8bb121f4 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalServicePackageOfferingDTO.java @@ -0,0 +1,65 @@ +package br.edu.utfpr.servicebook.model.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.HashSet; +import java.util.Set; + +@Data +@NoArgsConstructor +public class ProfessionalServicePackageOfferingDTO { + private Long id; + + public enum Type { + INDIVIDUAL, + COMBINED_PACKAGE, + SIMPLE_PACKAGE + } + + private ProfessionalServiceOfferingDTO.Type type; + /** + * Nome do serviço. + * O profissional pode customizar o nome do serviço cadastrado pelo administrador de várias maneiras, dependendo + * do tipo de particularidade que o seu serviço tem. + * Caso ele não especifique o nome do serviço, o nome do serviço cadastrado pelo administrador será usado. + */ + private String name; + + /** + * Descrição do serviço em primeira pessoa. + * O profissional pode customizar a descrição do serviço cadastrado pelo administrador de várias maneiras, dependendo + * do tipo de particularidade que o seu serviço tem. + * Caso ele não especifique a descrição do serviço, a descrição do serviço cadastrado pelo administrador será usada. + */ + private String description; + + /** + * Unidade de preço do serviço. + */ + private String unit; + + /** + * Duração do serviço. + */ + private String duration; + + private Integer amount; + + /** + * Serviço cadastrado pelo administrador. + * O profissional pode customizar a descrição do serviço cadastrado pelo administrador de várias maneiras, dependendo + * do tipo de particularidade que o seu serviço tem. + */ + private ServiceDTO service; + + private Long serviceId; + private Long price; + + /** + * Profissional que oferece o serviço. + */ + private UserDTO user; + + private Long userId; +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOffering.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOffering.java index ff6474ec..0291489b 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOffering.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOffering.java @@ -23,6 +23,19 @@ public class ProfessionalServiceOffering { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + public enum Type { + INDIVIDUAL, + COMBINED_PACKAGE, + SIMPLE_PACKAGE + } + + /** + * Tipo de anúncio. + */ + @Enumerated(EnumType.STRING) + private ProfessionalServiceOffering.Type type; + + /** * Nome do serviço. * O profissional pode customizar o nome do serviço cadastrado pelo administrador de várias maneiras, dependendo @@ -46,6 +59,16 @@ public class ProfessionalServiceOffering { */ private Long price; + /** + * Unidade de preço do serviço. + */ + private String unit; + + /** + * Duração do serviço. + */ + private String duration; + /** * Serviço cadastrado pelo administrador. * O profissional pode customizar a descrição do serviço cadastrado pelo administrador de várias maneiras, dependendo diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOfferingAdItemPK.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOfferingAdItemPK.java index a8aa64a2..ad03b0ab 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOfferingAdItemPK.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOfferingAdItemPK.java @@ -16,6 +16,7 @@ @AllArgsConstructor @Embeddable public class ProfessionalServiceOfferingAdItemPK implements Serializable { + Long professionalServiceOfferingId; Long professionalServiceOfferingAdId; diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServicePackageOffering.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServicePackageOffering.java index 88bc74f1..1a043cd5 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServicePackageOffering.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServicePackageOffering.java @@ -64,6 +64,21 @@ public enum Type { */ private Long price; + /** + * Unidade de preço do serviço. + */ + private String unit; + + /** + * Duração do serviço. + */ + private String duration; + + /** + * Quantidade, para o pacote de serviços. + * */ + private Integer amount; + /** * Usuário que criou o anúncio. */ @@ -75,4 +90,13 @@ public enum Type { */ @ManyToOne private Expertise expertise; + + /** + * Serviço cadastrado pelo administrador. + * O profissional pode customizar a descrição do serviço cadastrado pelo administrador de várias maneiras, dependendo + * do tipo de particularidade que o seu serviço tem. + */ + @ManyToOne + @JoinColumn(name = "service_id") + private Service service; } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingAdItemRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingAdItemRepository.java index 9abab248..48abac00 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingAdItemRepository.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingAdItemRepository.java @@ -1,9 +1,8 @@ package br.edu.utfpr.servicebook.model.repository; -import br.edu.utfpr.servicebook.model.entity.ProfessionalServicePackageOffering; -import br.edu.utfpr.servicebook.model.entity.ProfessionalServiceOfferingAdItem; -import br.edu.utfpr.servicebook.model.entity.ProfessionalServiceOfferingAdItemPK; +import br.edu.utfpr.servicebook.model.entity.*; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import java.util.List; @@ -17,9 +16,23 @@ public interface ProfessionalServiceOfferingAdItemRepository extends JpaReposito */ List findAllByProfessionalServicePackageOffering(ProfessionalServicePackageOffering professionalServicePackageOffering); + /** + * Retorna os serviços que o usuário possui. + * @param user + * @return + */ +// @Query("SELECT u FROM ProfessionalServiceOffering u WHERE EXISTS (SELECT pe FROM ProfessionalServicePackageOffering pe WHERE pe.user = :user)") +// List findProfessionalServiceOfferingAdItemsByUser(User user); +// @Query("SELECT u FROM ProfessionalServiceOffering u JOIN u.packageOfferings pe WHERE pe.user = :user") +// List findProfessionalServiceOfferingAdItemsByUser(User user); +// + @Query("SELECT u FROM ProfessionalServiceOfferingAdItem u JOIN u.professionalServiceOffering pso JOIN u.professionalServicePackageOffering jspo") + List findProfessionalServiceOfferingAdItemsByUserJoin(User user); - + @Query("SELECT psa FROM ProfessionalServiceOfferingAdItem psa " + + "JOIN FETCH psa.professionalServiceOffering pso") + List findProfessionalServiceOfferingAdItemsWithRelatedEntities(); } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingRepository.java index b792a723..113c0519 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingRepository.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingRepository.java @@ -1,6 +1,8 @@ package br.edu.utfpr.servicebook.model.repository; import br.edu.utfpr.servicebook.model.entity.*; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @@ -18,6 +20,8 @@ public interface ProfessionalServiceOfferingRepository extends JpaRepository findProfessionalServiceOfferingByUser(User user); + public List findFirst3ByUserAndType(User user, Enum type); + public List findByUserAndType(User user, Enum type); /** * Busca todas os serviços de um profissional @@ -63,6 +67,22 @@ public interface ProfessionalServiceOfferingRepository extends JpaRepository findProfessionalServiceOfferingByName(String name); + @Query("SELECT e FROM ProfessionalServiceOffering e WHERE e.service = :id") + public Optional findProfessionalServiceOfferingById(Long id); + /** + * Retorna os serviços que o usuário possui. + * @param user + * @return + */ + @Query("SELECT u FROM ProfessionalServiceOfferingAdItem u WHERE EXISTS (SELECT pe FROM ProfessionalServiceOffering pe WHERE pe.user = :user)") + List findProfessionalServiceOfferingAdItemsByUser(User user); + + @Query("SELECT u FROM ProfessionalServiceOffering u JOIN ProfessionalServiceOfferingAdItem r WHERE r.professionalServiceOffering.id = u.id") + public List findProfessionalServiceOfferingAdItemsByUserJoin(User user); + + @Query("SELECT u FROM ProfessionalServiceOfferingAdItem u JOIN FETCH u.professionalServicePackageOffering") + List findDistinctProfessionalServiceOfferings(); + } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServicePackageOfferingRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServicePackageOfferingRepository.java index ab0a9054..fe10e36a 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServicePackageOfferingRepository.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServicePackageOfferingRepository.java @@ -24,5 +24,8 @@ public interface ProfessionalServicePackageOfferingRepository extends JpaReposit /** * Busca os anúncios de um dado profissional. */ - public List findAllByUser(User user); + public List findFirst3ByUserAndType(User user, Enum type); + + public List findByUserAndType(User user, Enum type); + } diff --git a/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingAdItemService.java b/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingAdItemService.java index f115142b..cd87a864 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingAdItemService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingAdItemService.java @@ -1,7 +1,9 @@ package br.edu.utfpr.servicebook.service; +import br.edu.utfpr.servicebook.model.entity.ProfessionalServiceOffering; import br.edu.utfpr.servicebook.model.entity.ProfessionalServicePackageOffering; import br.edu.utfpr.servicebook.model.entity.ProfessionalServiceOfferingAdItem; +import br.edu.utfpr.servicebook.model.entity.User; import br.edu.utfpr.servicebook.model.repository.ProfessionalServiceOfferingAdItemRepository; import org.springframework.beans.factory.annotation.Autowired; @@ -16,4 +18,16 @@ public class ProfessionalServiceOfferingAdItemService { public List findAllByProfessionalServicePackageOffering(ProfessionalServicePackageOffering professionalServicePackageOffering){ return professionalServiceOfferingAdItemRepository.findAllByProfessionalServicePackageOffering(professionalServicePackageOffering); } + +// /** +// * Salva uma oferta de serviço de um profissional +// * @param professionalServiceOfferingAdItem +// */ + public ProfessionalServiceOfferingAdItem save(ProfessionalServiceOfferingAdItem professionalServiceOfferingAdItem){ + return this.professionalServiceOfferingAdItemRepository.save(professionalServiceOfferingAdItem); + } + + public List findAllByProfessionalServicePackageOfferingUser(){ + return professionalServiceOfferingAdItemRepository.findProfessionalServiceOfferingAdItemsWithRelatedEntities(); + } } diff --git a/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingService.java b/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingService.java index 59ca9a31..a7f0a048 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingService.java @@ -7,6 +7,8 @@ import br.edu.utfpr.servicebook.model.repository.CategoryRepository; import br.edu.utfpr.servicebook.model.repository.ProfessionalServiceOfferingRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.repository.Query; import java.util.List; import java.util.Optional; @@ -50,6 +52,13 @@ public List findProfessionalServiceOfferingByUser(U return professionalServiceOfferingRepository.findProfessionalServiceOfferingByUser(user); } + public List findFirst3ProfessionalServiceOfferingByUserAndType(User user, Enum type){ + return professionalServiceOfferingRepository.findFirst3ByUserAndType(user, type); + } + + public List findProfessionalServiceOfferingByUserAndType(User user, Enum type){ + return professionalServiceOfferingRepository.findByUserAndType(user, type); + } /** * Busca todas as ofertas de serviços de um profissional * @param id @@ -97,4 +106,21 @@ public List findProfessionalServiceOfferingByUserAn public Optional findProfessionalServiceOfferingByName(String name){ return professionalServiceOfferingRepository.findProfessionalServiceOfferingByName(name); } + + /** + * Busca o serviço pelo id. + * @param id + * @return + */ + public Optional findProfessionalServiceOfferingByName(Long id){ + return professionalServiceOfferingRepository.findProfessionalServiceOfferingById(id); + } + + public List findAllByProfessionalServicePackageOfferingUser(User professionalServicePackageOffering){ + return professionalServiceOfferingRepository.findProfessionalServiceOfferingAdItemsByUser(professionalServicePackageOffering); + } + + public List findAll(){ + return professionalServiceOfferingRepository.findDistinctProfessionalServiceOfferings(); + } } diff --git a/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServicePackageOfferingService.java b/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServicePackageOfferingService.java index 2dd243c3..dc16ef6b 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServicePackageOfferingService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServicePackageOfferingService.java @@ -32,7 +32,23 @@ public List findAllByUserAndExpertise(User u /** * Busca os anúncios de pacote de serviços de um dado profissional. */ - public List findAllByUser(User user){ - return this.professionalServicePackageOfferingRepository.findAllByUser(user); + public List findAllByUserAndType(User user, Enum type){ + return this.professionalServicePackageOfferingRepository.findFirst3ByUserAndType(user, type); + } + + /** + * Salva uma oferta de serviço de um profissional + * @param professionalServicePackageOffering + */ + public void save(ProfessionalServicePackageOffering professionalServicePackageOffering){ + professionalServicePackageOfferingRepository.save(professionalServicePackageOffering); + } + + public ProfessionalServicePackageOffering findById(Long id) { + return professionalServicePackageOfferingRepository.findById(id).orElse(null); + } + + public List findByTypeAndUser(User user, Enum type) { + return professionalServicePackageOfferingRepository.findByUserAndType(user,type); } } diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 899bf343..bac1e594 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -88,9 +88,19 @@ INSERT INTO services (name, description, allow_scheduling, path_icon, expertise_ VALUES ('Balanceamento', 'Balanceamento das rodas', false, 'https://res.cloudinary.com/dgueb0wir/image/upload/v1689176876/servicebook/expertises/mecanico_quczum.svg', 4), ('Troca de óleo', 'Troca do óleo do motor', false, 'https://res.cloudinary.com/dgueb0wir/image/upload/v1689176876/servicebook/expertises/mecanico_quczum.svg', 4); -INSERT INTO professional_service_offerings (name, description, service_id, user_id) -VALUES ('Balanceamento com máquina importada', 'O balanceamento com 100% de garantia', 1, 2), - (null, null, 2, 2); +-- INSERT INTO professional_service_offerings (name, description, price, unit, duration, service_id, user_id, type, id) +-- VALUES ('Balanceamento com máquina importada', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'INDIVIDUAL', 1); +-- ('Balanceamento com máquina importada1', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'INDIVIDUAL', 2), +-- ('Balanceamento com máquina importada2', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'INDIVIDUAL', 3), +-- ('Balanceamento com máquina importada3', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'INDIVIDUAL', 4); +-- (null, null, 2, 2); + +-- INSERT INTO professional_service_package_offering (name, description, price, unit, duration, service_id, user_id, type, amount,id) +-- VALUES ('Balanceamento com máquina importada', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'SIMPLE_PACKAGE', 2, 1), +-- ('Balanceamento com máquina importada', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'SIMPLE_PACKAGE', 2, 2), +-- ('Balanceamento com máquina importada', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'SIMPLE_PACKAGE', 2, 3), +-- ('Balanceamento com máquina importada', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'SIMPLE_PACKAGE', 2, 4), +-- ('Balanceamento com máquina importada', 'O balanceamento com 100% de garantia', 19000, 'Hora', '2 Horas', 1, 2, 'SIMPLE_PACKAGE', 2, 5); INSERT INTO companies (cnpj, id) VALUES ('98.988.640/0001-91', 7); diff --git a/src/main/webapp/WEB-INF/tags/my-ads-combined.tag b/src/main/webapp/WEB-INF/tags/my-ads-combined.tag new file mode 100644 index 00000000..e3a8891c --- /dev/null +++ b/src/main/webapp/WEB-INF/tags/my-ads-combined.tag @@ -0,0 +1,37 @@ +<%@tag description="Servicebook - Banner template" pageEncoding="UTF-8" %> +<%@attribute name="cities" type="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + +<%@ attribute name="items" required="false" type="java.util.ArrayList"%> + + +
+ Serviços Combinados + ver mais + +
+ +
+
+
+ ${service.name} +

${service.name}

+
+
+ ${service.name} + ${service.description} +
+
+
+
+ R$ +
+ +
+ access_time ${service.duration} +
+
+
+
+
+
diff --git a/src/main/webapp/WEB-INF/tags/my-ads-package.tag b/src/main/webapp/WEB-INF/tags/my-ads-package.tag new file mode 100644 index 00000000..12b50929 --- /dev/null +++ b/src/main/webapp/WEB-INF/tags/my-ads-package.tag @@ -0,0 +1,35 @@ +<%@tag description="Servicebook - Banner template" pageEncoding="UTF-8" %> +<%@attribute name="cities" type="java.util.List" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + +<%@ attribute name="itemsService" required="false" type="java.util.ArrayList" %> + +
+ Pacote de Serviços + ver mais +
+ +
+
+
+ ${service.name} +

Pacote com ${service.amount} ${service.name}

+
+
+ ${service.name} + ${service.description} +
+
+
+
+ R$ +
+ +
+ access_time ${service.duration} +
+
+
+
+
+
diff --git a/src/main/webapp/WEB-INF/tags/navbar-professional.tag b/src/main/webapp/WEB-INF/tags/navbar-professional.tag index c58cc98c..288902ab 100644 --- a/src/main/webapp/WEB-INF/tags/navbar-professional.tag +++ b/src/main/webapp/WEB-INF/tags/navbar-professional.tag @@ -63,6 +63,7 @@ ${userInfo.name}
  • +
  • Meus Anúncios
  • Minha Conta
  • Meu Perfil
  • diff --git a/src/main/webapp/WEB-INF/view/professional/ads/my-ads-combineds.jsp b/src/main/webapp/WEB-INF/view/professional/ads/my-ads-combineds.jsp new file mode 100644 index 00000000..e7b32ee7 --- /dev/null +++ b/src/main/webapp/WEB-INF/view/professional/ads/my-ads-combineds.jsp @@ -0,0 +1,97 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + +
    +
    +
    +
    + + + + +
    +

    Meus Anúncios

    +
    +
    +

    Serviços Combinados.

    +
    + +
    + +
    + + +
    +
    +
    + ${service.name}more_vert +

    ${service.name}

    +
    +
    + ${service.name}close + ${service.name} +
    +
    +
    +
    + R$ +
    + +
    + access_time ${service.duration} +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/professional/ads/my-ads-individuals.jsp b/src/main/webapp/WEB-INF/view/professional/ads/my-ads-individuals.jsp new file mode 100644 index 00000000..c30f7791 --- /dev/null +++ b/src/main/webapp/WEB-INF/view/professional/ads/my-ads-individuals.jsp @@ -0,0 +1,97 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + +
    +
    +
    +
    + + + + +
    +

    Meus Anúncios

    +
    +
    +

    Serviços Individuais.

    +
    + +
    + +
    + + +
    +
    +
    + ${service.service.name}more_vert +

    ${service.name}

    +
    +
    + ${service.name}close + ${service.description} +
    +
    +
    +
    + R$ +
    + +
    + access_time ${service.duration} +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/professional/ads/my-ads-packages.jsp b/src/main/webapp/WEB-INF/view/professional/ads/my-ads-packages.jsp new file mode 100644 index 00000000..532a475a --- /dev/null +++ b/src/main/webapp/WEB-INF/view/professional/ads/my-ads-packages.jsp @@ -0,0 +1,97 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + + + + + + + + +
    +
    +
    +
    + + + + +
    +

    Meus Anúncios

    +
    +
    +

    Pacotes de Serviços.

    +
    + +
    + +
    + + +
    +
    +
    + ${service.name}more_vert +

    Pacote com ${service.amount} ${service.name}

    +
    +
    + ${service.name}close + Pacote contendo ${service.amount} ${service.name} +
    +
    +
    +
    + R$ +
    + +
    + access_time ${service.duration} +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/professional/my-ads-register-combined.jsp b/src/main/webapp/WEB-INF/view/professional/my-ads-register-combined.jsp new file mode 100644 index 00000000..169b3165 --- /dev/null +++ b/src/main/webapp/WEB-INF/view/professional/my-ads-register-combined.jsp @@ -0,0 +1,80 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + +
    +
    + +
    +
    +

    Quais os serviços?

    + +
    + +
    +

    Titulo

    + + + + +

    + +

    + +
    + +
    +

    Qual a unidade de preço do serviço?

    + +
    + +
    +

    Quanto você cobra por este serviço?

    + + + +
    + +
    +

    Qual a Duração do serviço?

    + +
    + +
    +
    + Cancelar + +
    + +
    +
    + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/professional/my-ads-register-package.jsp b/src/main/webapp/WEB-INF/view/professional/my-ads-register-package.jsp new file mode 100644 index 00000000..7cea9a81 --- /dev/null +++ b/src/main/webapp/WEB-INF/view/professional/my-ads-register-package.jsp @@ -0,0 +1,84 @@ +<%@page contentType="text/html" pageEncoding="UTF-8" %> +<%@taglib prefix="t" tagdir="/WEB-INF/tags" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + +
    +
    + +
    + +
    +

    Qual o serviço?

    + +
    + +
    +

    Titulo

    + + +

    + +

    +
    + +
    +

    Qual a unidade de preço do serviço?

    + +
    + +
    +

    Quanto você cobra por este serviço?

    + + + +
    + +
    +

    Qual a quantidade para o pacote?

    + +
    + +
    +

    Qual a Duração do serviço?

    + +
    + +
    +
    + Cancelar + +
    + +
    +
    + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/professional/my-ads-register.jsp b/src/main/webapp/WEB-INF/view/professional/my-ads-register.jsp index 68127361..a04c56f3 100644 --- a/src/main/webapp/WEB-INF/view/professional/my-ads-register.jsp +++ b/src/main/webapp/WEB-INF/view/professional/my-ads-register.jsp @@ -18,7 +18,7 @@
    -

    Anúnciar Serviço

    +

    Anunciar Serviços

    @@ -33,36 +33,33 @@

    -
    -
    +
    +

    Qual o tipo do serviço?

    + +
    + + + +
    +
    +
    -
    -

    Qual o tipo do serviço?

    - -
    - -
    - -<%--
    --%> -<%--

    Qual a especialidade?

    --%> -<%-- --%> -<%--
    --%>

    Qual o serviço?

    - @@ -72,19 +69,19 @@

    Titulo

    - + +

    - +

    -
    -

    Qual a unidade de preço do serviço/

    - @@ -94,17 +91,13 @@

    Quanto você cobra por este serviço?

    - -
    - -

    Qual a Duração do serviço?

    - @@ -117,6 +110,12 @@
    +
    + Cancelar + +
    @@ -129,50 +128,8 @@ \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/professional/my-ads.jsp b/src/main/webapp/WEB-INF/view/professional/my-ads.jsp index 88a753c0..7f2a8288 100644 --- a/src/main/webapp/WEB-INF/view/professional/my-ads.jsp +++ b/src/main/webapp/WEB-INF/view/professional/my-ads.jsp @@ -3,91 +3,126 @@ <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> - - + + + - -
    -
    -
    -
    + +
    +
    +
    +
    + - + -
    -

    Meus Anúncios

    -
    -
    -

    Adicione anúncios dos serviços que você oferece dentro do Servicebook.

    -

    Se ativado o agendamento, o cliente possuira acesso a sua agenda, podendo visualizar os dias e horários - disponíveis. Além disso, você pode adicioanar o preço e duração dos seus serviços, dessa forma - permitindo que clientes adquiram seus serviços de forma rápida.

    -
    - -
    - +
    +

    Meus Anúncios

    +
    +
    +

    Adicione anúncios dos serviços que você oferece dentro do Servicebook.

    +

    Se ativado o agendamento, o cliente possuira acesso a sua agenda, podendo visualizar os dias e horários + disponíveis. Além disso, você pode adicioanar o preço e duração dos seus serviços, dessa forma + permitindo que clientes adquiram seus serviços de forma rápida.

    +
    + +
    + +
    + + + + + +
    Serviços Individuais
    + +
    + + + + +
    + Serviços Individuais + ver mais +
    +
    +
    +
    + ${service.service.name} +

    ${service.name}

    +
    +
    + ${service.name} + ${service.description} +
    +
    +
    +
    + R$
    - -
    - +
    + access_time ${service.duration}
    - +
    +
    + + + +
    + +
    Serviços Combinados
    + +
    + + + +
    -
    - - - - +
    +
    -
    +
    \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/professional/my-ads.jsp b/src/main/webapp/WEB-INF/view/professional/my-ads.jsp index 7f2a8288..c9c15fa3 100644 --- a/src/main/webapp/WEB-INF/view/professional/my-ads.jsp +++ b/src/main/webapp/WEB-INF/view/professional/my-ads.jsp @@ -1,6 +1,7 @@ <%@page contentType="text/html" pageEncoding="UTF-8" %> <%@taglib prefix="t" tagdir="/WEB-INF/tags" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix = "fmt" uri = "http://java.sun.com/jsp/jstl/fmt" %> @@ -34,10 +35,10 @@
    - + + +
    @@ -51,52 +52,58 @@
    +
    +
    Serviços Individuais
    -
    - Serviços Individuais - ver mais + Serviços Individuais + ver mais navigate_next
    -
    -
    -
    - ${service.service.name} -

    ${service.name}

    -
    -
    - ${service.name} - ${service.description} + + +
    +

    ${service.service.expertise.name}

    +
    +
    + ${service.duration}
    -
    +
    -
    - R$ -
    - -
    - access_time ${service.duration} + +
    + +
    +
    + +
    + ${service.description}
    +
    +

    +
    +

    ${service.service.name}

    +
    - +
    Serviços Combinados
    - - + +
    @@ -125,17 +132,13 @@ $('.ads-price').mask('0?00.0?00.0?00.0?00,00', {reverse: true}); //inicializa o select de serviços com os serviços da especialidade selecionada - $('#expertise-select').change(function () { + $('#expertise-select-filter').change(function () { let expertiseId = $(this).val(); - let url = 'minha-conta/profissional/especialidades/' + expertiseId + '/servicos'; + let url = 'minha-conta/profissional/meus-anuncios/especialidade/' + expertiseId; $.get(url, function (data) { - let options = ''; - data.forEach(function (service) { - options += ''; - }); - $('#service-select').html(options); - $('#service-select').formSelect(); + + $('#ads').html(data); }); }); }); diff --git a/src/main/webapp/assets/resources/scripts/main.js b/src/main/webapp/assets/resources/scripts/main.js index 000f4213..693fcd85 100644 --- a/src/main/webapp/assets/resources/scripts/main.js +++ b/src/main/webapp/assets/resources/scripts/main.js @@ -103,9 +103,9 @@ $(document).ready(function (){ $('#type-combined').hide(); } if(type == 'INDIVIDUAL'){ - $('#type-individual').show(); + $('.type-individual').show(); }else { - $('#type-individual').hide(); + $('.type-individual').hide(); } }); @@ -152,6 +152,7 @@ $(document).ready(function (){ $('.sobrescrever').change(function () { var elements = document.getElementsByClassName('ads-name-individual'); var package = document.getElementById('ads-name-package'); + var ads = document.getElementById('ads-name-individual'); if (!package.disabled) { package.disabled = true; @@ -159,6 +160,12 @@ $(document).ready(function (){ package.disabled = false; } + if (!ads.disabled) { + ads.disabled = true; + } else { + ads.disabled = false; + } + for (var i = 0; i < elements.length; i++) { var element = elements[i]; if (!element.disabled) { @@ -171,6 +178,35 @@ $(document).ready(function (){ }); }); +//inicializa o select de serviços com os serviços da especialidade selecionada +$('#expertise-select-package').change(function () { + let expertiseId = $(this).val(); + let url = 'minha-conta/profissional/especialidades/' + expertiseId + '/servicos'; + + $.get(url, function (data) { + let options = ''; + data.forEach(function (service) { + options += ''; + }); + $('#service-select-package').html(options); + $('#service-select-package').formSelect(); + }); +}); + +//inicializa o select de serviços com os serviços da especialidade selecionada +$('#expertise-select-combined').change(function () { + let expertiseId = $(this).val(); + let url = 'minha-conta/profissional/especialidades/' + expertiseId + '/servicos'; + + $.get(url, function (data) { + let options = ''; + data.forEach(function (service) { + options += ''; + }); + $('#mySelect').html(options); + $('#mySelect').formSelect(); + }); +}); // remove a mascara no campo de valor, para quando enviar pro controller não dar erro de conversão function RemoveMaskIndividual() { @@ -197,7 +233,7 @@ function mostrarSelecionados() { var selecionadosIds = []; // Adiciona os valores selecionados como itens de lista - for (var i = 0; i < select.options.length; i++) { + for (var i = 1; i < select.options.length; i++) { if (select.options[i].selected && select.options[i].value !== "") { selecionados.push(select.options[i].text); selecionadosIds.push(select.options[i].value); diff --git a/src/main/webapp/assets/resources/styles/professional/ads.css b/src/main/webapp/assets/resources/styles/professional/ads.css index 7eaa1906..b6983d8f 100644 --- a/src/main/webapp/assets/resources/styles/professional/ads.css +++ b/src/main/webapp/assets/resources/styles/professional/ads.css @@ -9,6 +9,44 @@ font-size: .75rem !important; } +/*MEUS ANUNCIOS*/ +.card .card-content{ + padding: 13px !important; +} +.label_price{ + /*background-color: #333333;*/ + background-color: #81C5F3; + font-weight: bold; + font-size: 1rem; + text-align: center; + padding: 5px; +} +.label_duration{ + /*background-color: #333333;*/ + background-color: #81C5F3; + font-weight: bold; + font-size: 1rem; + text-align: center; + padding: 5px; +} +.label_especialidade{ + background-color: #333333; + margin: 0; + color: white; + font-weight: bold; + text-align: center; +} + +.div_cards_services{ + margin: 10px 0 30px; +} + +.btn_view{ + /*float: right;*/ + float: right; + color: #1194e5 !important; + font-weight: bold; +} /*.card{*/ /* height: 100%;*/ /*}*/ @@ -34,3 +72,9 @@ color: black !important; } + +/*CADASTRO*/ +.div_text_section{ + margin: 5px 5px 0 !important; + font-weight: bold; +} From 9330307287d50a28ad3b831e55b187463ff8a7ee Mon Sep 17 00:00:00 2001 From: taisHryssai Date: Tue, 24 Oct 2023 22:22:41 -0300 Subject: [PATCH 5/9] adjust my ads --- src/main/webapp/WEB-INF/view/professional/my-ads.jsp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/main/webapp/WEB-INF/view/professional/my-ads.jsp b/src/main/webapp/WEB-INF/view/professional/my-ads.jsp index c9c15fa3..774f9beb 100644 --- a/src/main/webapp/WEB-INF/view/professional/my-ads.jsp +++ b/src/main/webapp/WEB-INF/view/professional/my-ads.jsp @@ -34,15 +34,6 @@ permitindo que clientes adquiram seus serviços de forma rápida.

    -
    - -
    -
    From 16f4973e990a5ef1e32ffa8d4b014a38f3ab5d7a Mon Sep 17 00:00:00 2001 From: taisHryssai Date: Wed, 1 Nov 2023 23:13:00 -0300 Subject: [PATCH 6/9] Simple Search --- .../controller/IndexController.java | 66 ++++++++++- .../controller/ProfessionalController.java | 9 ++ .../ProfessionalServiceOfferingMapper.java | 9 +- ...ProfessionalServiceOfferingRepository.java | 10 +- .../ProfessionalServiceOfferingService.java | 12 +- .../servicebook/service/ServiceService.java | 1 + src/main/webapp/WEB-INF/tags/search-bar.tag | 109 +++++++++++++----- src/main/webapp/WEB-INF/tags/template.tag | 5 + .../webapp/WEB-INF/view/visitor/index.jsp | 59 +++++++++- .../WEB-INF/view/visitor/search-results.jsp | 1 + .../libraries/select2/css/select2.min.css | 1 + .../libraries/select2/js/select2.min.js | 2 + .../webapp/assets/resources/scripts/main.js | 2 +- 13 files changed, 242 insertions(+), 44 deletions(-) create mode 100644 src/main/webapp/assets/libraries/select2/css/select2.min.css create mode 100644 src/main/webapp/assets/libraries/select2/js/select2.min.js diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/IndexController.java b/src/main/java/br/edu/utfpr/servicebook/controller/IndexController.java index e1c2b3bd..922385d1 100644 --- a/src/main/java/br/edu/utfpr/servicebook/controller/IndexController.java +++ b/src/main/java/br/edu/utfpr/servicebook/controller/IndexController.java @@ -1,7 +1,13 @@ package br.edu.utfpr.servicebook.controller; +import br.edu.utfpr.servicebook.model.dto.CategoryDTO; +import br.edu.utfpr.servicebook.model.dto.ExpertiseDTO; import br.edu.utfpr.servicebook.model.dto.JobRequestFullDTO; +import br.edu.utfpr.servicebook.model.dto.ServiceDTO; import br.edu.utfpr.servicebook.model.entity.*; +import br.edu.utfpr.servicebook.model.mapper.CategoryMapper; +import br.edu.utfpr.servicebook.model.mapper.ExpertiseMapper; +import br.edu.utfpr.servicebook.model.mapper.ServiceMapper; import br.edu.utfpr.servicebook.security.IAuthentication; import br.edu.utfpr.servicebook.security.RoleType; import br.edu.utfpr.servicebook.service.*; @@ -15,20 +21,20 @@ import org.springframework.data.domain.Page; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.annotation.security.PermitAll; import javax.annotation.security.RolesAllowed; +import javax.persistence.EntityNotFoundException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; @RequestMapping("/") @Controller @@ -61,6 +67,20 @@ public class IndexController { @Autowired private HttpSession httpSession; + @Autowired + private CategoryService categoryService; + + @Autowired + private CategoryMapper categoryMapper; + + @Autowired + private ExpertiseMapper expertiseMapper; + + @Autowired + private ServiceService serviceService; + + @Autowired + private ServiceMapper serviceMapper; @GetMapping @PermitAll public ModelAndView showIndexPage(HttpServletResponse response) { @@ -81,6 +101,11 @@ public ModelAndView showIndexPage(HttpServletResponse response) { return new ModelAndView("redirect:/minha-conta/empresa/disponiveis"); } } + //lista de categorias + List categories = categoryService.findAll(); + List categoryDTOs = categories.stream() + .map(s -> categoryMapper.toDto(s)) + .collect(Collectors.toList()); List cities = cityService.findAll(); mv.addObject("cities", cities); @@ -90,6 +115,7 @@ public ModelAndView showIndexPage(HttpServletResponse response) { mv.addObject("totalJobContracted", jobContractedService.countAll()); mv.addObject("totalProfessionals", userService.countProfessionals()); mv.addObject("totalClients", userService.countUsersWithoutExpertise()); + mv.addObject("categories", categoryDTOs); return mv; } @@ -101,8 +127,6 @@ public String showClientPage(HttpSession httpSession, RedirectAttributes redirec return "redirect:/"; } - - @GetMapping("/bem-vindo") @PermitAll public ModelAndView showWelcomePage() { @@ -122,4 +146,36 @@ public String notAuthorized() { return "error/not-authorized"; } + @GetMapping("/especialidades/categoria/{categoryId}") + @PermitAll + @ResponseBody + public List showExpertisesByCategory(@PathVariable Long categoryId) throws Exception { + Optional oCategory = categoryService.findById(categoryId); + + Category category = categoryService.findById(categoryId).orElseThrow(() -> new EntityNotFoundException("Categoria não encontrada")); + + List expertises = expertiseService.findByCategoryId(categoryId); + + List expertiseDTOS = expertises.stream() + .map(s -> expertiseMapper.toDto(s)) + .collect(Collectors.toList()); + + return expertiseDTOS; + } + + @GetMapping("/servicos/especialidade/{expertiseId}") + @PermitAll + @ResponseBody + public List showServicesByExpertise(@PathVariable Long expertiseId) throws Exception { + + Expertise expertise = expertiseService.findById(expertiseId).orElseThrow(() -> new EntityNotFoundException("Especialidade não encontrada")); + + List services = serviceService.findByExpertise(expertise); + + List servicesDTO = services.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); + + return servicesDTO; + } } \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/ProfessionalController.java b/src/main/java/br/edu/utfpr/servicebook/controller/ProfessionalController.java index e64b516c..e6f9b95b 100644 --- a/src/main/java/br/edu/utfpr/servicebook/controller/ProfessionalController.java +++ b/src/main/java/br/edu/utfpr/servicebook/controller/ProfessionalController.java @@ -115,6 +115,7 @@ protected ModelAndView showAll() throws Exception { @PermitAll protected ModelAndView showSearchResults( @RequestParam(value = "termo-da-busca") String searchTerm, + // @RequestParam(value = "serviceId") String searchService, @RequestParam(value = "pag", defaultValue = "1") int page ) throws Exception { ModelAndView mv = new ModelAndView("visitor/search-results"); @@ -134,12 +135,20 @@ protected ModelAndView showSearchResults( } Page professionals = individualService.findDistinctByTermIgnoreCaseWithPagination(searchTerm, page, size); + Page serviceOfferings = professionalServiceOfferingService.findDistinctByTermIgnoreCaseWithPagination(searchTerm, page, size); + List professionalSearchItemDTOS = professionals.stream() .map(s -> individualMapper.toSearchItemDto(s, individualService.getExpertises(s))) .collect(Collectors.toList()); + List professionalServiceOfferingDTOS = serviceOfferings.stream() + .map(s -> professionalServiceOfferingMapper.toSearchItemDto(s)) + .collect(Collectors.toList()); + + PaginationDTO paginationDTO = paginationUtil.getPaginationDTO(professionals, "/profissionais/busca?termo-da-busca="+ searchTerm); mv.addObject("professionals", professionalSearchItemDTOS); + mv.addObject("professionalServiceOfferingDTOS", professionalServiceOfferingDTOS); mv.addObject("pagination", paginationDTO); mv.addObject("isParam", true); mv.addObject("searchTerm", searchTerm); diff --git a/src/main/java/br/edu/utfpr/servicebook/model/mapper/ProfessionalServiceOfferingMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/ProfessionalServiceOfferingMapper.java index 80956a23..60a6f007 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/mapper/ProfessionalServiceOfferingMapper.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/ProfessionalServiceOfferingMapper.java @@ -1,9 +1,6 @@ package br.edu.utfpr.servicebook.model.mapper; -import br.edu.utfpr.servicebook.model.dto.AddressDTO; -import br.edu.utfpr.servicebook.model.dto.ProfessionalServiceOfferingDTO; -import br.edu.utfpr.servicebook.model.entity.Address; -import br.edu.utfpr.servicebook.model.entity.City; +import br.edu.utfpr.servicebook.model.dto.*; import br.edu.utfpr.servicebook.model.entity.ProfessionalServiceOffering; import org.modelmapper.ModelMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -25,4 +22,8 @@ public ProfessionalServiceOffering toEntity(ProfessionalServiceOfferingDTO dto){ return entity; } + public ProfessionalServiceOfferingDTO toSearchItemDto(ProfessionalServiceOffering entity){ + ProfessionalServiceOfferingDTO dto = mapper.map(entity, ProfessionalServiceOfferingDTO.class); + return dto; + } } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingRepository.java index b792a723..8f272b8b 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingRepository.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/ProfessionalServiceOfferingRepository.java @@ -1,6 +1,8 @@ package br.edu.utfpr.servicebook.model.repository; import br.edu.utfpr.servicebook.model.entity.*; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @@ -63,6 +65,12 @@ public interface ProfessionalServiceOfferingRepository extends JpaRepository findProfessionalServiceOfferingByName(String name); - + @Query("select distinct p from ProfessionalServiceOffering p left join Service pe on p.service = pe where " + + "lower(p.name) like lower(concat('%', :term, '%'))" + + "or lower(p.description) like lower(concat('%', :term, '%')) " + + "or lower(pe.expertise.name) like lower(concat('%', :term, '%'))") + Page findDistinctByTermIgnoreCaseWithPagination( + String term, + Pageable pageable); } diff --git a/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingService.java b/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingService.java index 59ca9a31..b69264fd 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/ProfessionalServiceOfferingService.java @@ -1,12 +1,11 @@ package br.edu.utfpr.servicebook.service; -import br.edu.utfpr.servicebook.model.entity.Expertise; -import br.edu.utfpr.servicebook.model.entity.ProfessionalServiceOffering; -import br.edu.utfpr.servicebook.model.entity.Service; -import br.edu.utfpr.servicebook.model.entity.User; +import br.edu.utfpr.servicebook.model.entity.*; import br.edu.utfpr.servicebook.model.repository.CategoryRepository; import br.edu.utfpr.servicebook.model.repository.ProfessionalServiceOfferingRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.repository.Query; import java.util.List; import java.util.Optional; @@ -68,6 +67,11 @@ public List findProfessionalServiceOfferingByServic return professionalServiceOfferingRepository.findProfessionalServiceOfferingByService(service); } + public Page findDistinctByTermIgnoreCaseWithPagination(String searchTerm, Integer page, Integer size){ + PageRequest pageRequest = PageRequest.of(page - 1, size); + return this.professionalServiceOfferingRepository.findDistinctByTermIgnoreCaseWithPagination(searchTerm, pageRequest); + } + /** * Busca todas os serviços de um profissional por serviço cadastrado pelo administrador. */ diff --git a/src/main/java/br/edu/utfpr/servicebook/service/ServiceService.java b/src/main/java/br/edu/utfpr/servicebook/service/ServiceService.java index 09450fe8..ba373f91 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/ServiceService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/ServiceService.java @@ -6,6 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; diff --git a/src/main/webapp/WEB-INF/tags/search-bar.tag b/src/main/webapp/WEB-INF/tags/search-bar.tag index dde28e28..41307754 100644 --- a/src/main/webapp/WEB-INF/tags/search-bar.tag +++ b/src/main/webapp/WEB-INF/tags/search-bar.tag @@ -1,33 +1,88 @@ <%@tag description="Servicebook - Search bar template" pageEncoding="UTF-8" %> +<%@attribute name="items" type="java.util.ArrayList" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + + +
    -
    -
    -
    -

    O QUE VOCÊ PRECISA?

    +
    +
    +
    +

    O QUE VOCÊ PRECISA?

    +
    Nos informe de qual serviço você precisa e escolha o melhor profissional!
    +
    +
    +
    +
    +
    + +
    +
    - -
    -
    - -
    -
    -
    -
    - -
    -
    -
    -
    -
    \ No newline at end of file +
    +
    + + +
    +
    + + +
    +
    +<%-- datalist--%> + + +
    + +
    +
    + +
    +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/tags/template.tag b/src/main/webapp/WEB-INF/tags/template.tag index dd89cfcb..6c07bfe8 100644 --- a/src/main/webapp/WEB-INF/tags/template.tag +++ b/src/main/webapp/WEB-INF/tags/template.tag @@ -16,6 +16,8 @@ + + @@ -131,12 +133,15 @@ src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"> + + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/view/visitor/search-results.jsp b/src/main/webapp/WEB-INF/view/visitor/search-results.jsp index d90d7530..1646e94c 100644 --- a/src/main/webapp/WEB-INF/view/visitor/search-results.jsp +++ b/src/main/webapp/WEB-INF/view/visitor/search-results.jsp @@ -17,6 +17,7 @@
    + ${professionalServiceOfferingDTOS}
    diff --git a/src/main/webapp/assets/libraries/select2/css/select2.min.css b/src/main/webapp/assets/libraries/select2/css/select2.min.css new file mode 100644 index 00000000..f00f1547 --- /dev/null +++ b/src/main/webapp/assets/libraries/select2/css/select2.min.css @@ -0,0 +1 @@ +.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{background-color:transparent;border:none;font-size:1em}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline;list-style:none;padding:0}.select2-container .select2-selection--multiple .select2-selection__clear{background-color:transparent;border:none;font-size:1em}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;margin-left:5px;padding:0;max-width:100%;resize:none;height:18px;vertical-align:bottom;font-family:sans-serif;overflow:hidden;word-break:keep-all}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option--selectable{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;height:26px;margin-right:20px;padding-right:0px}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;padding-bottom:5px;padding-right:5px;position:relative}.select2-container--default .select2-selection--multiple.select2-selection--clearable{padding-right:25px}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;font-weight:bold;height:20px;margin-right:10px;margin-top:5px;position:absolute;right:0;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:inline-block;margin-left:5px;margin-top:5px;padding:0;padding-left:20px;position:relative;max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:bottom;white-space:nowrap}.select2-container--default .select2-selection--multiple .select2-selection__choice__display{cursor:default;padding-left:2px;padding-right:5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{background-color:transparent;border:none;border-right:1px solid #aaa;border-top-left-radius:4px;border-bottom-left-radius:4px;color:#999;cursor:pointer;font-size:1em;font-weight:bold;padding:0 4px;position:absolute;left:0;top:0}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover,.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:focus{background-color:#f1f1f1;color:#333;outline:none}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__display{padding-left:5px;padding-right:2px}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{border-left:1px solid #aaa;border-right:none;border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:4px;border-bottom-right-radius:4px}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__clear{float:left;margin-left:10px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--group{padding:0}.select2-container--default .select2-results__option--disabled{color:#999}.select2-container--default .select2-results__option--selected{background-color:#ddd}.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;height:26px;margin-right:20px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0;padding-bottom:5px;padding-right:5px}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;display:inline-block;margin-left:5px;margin-top:5px;padding:0}.select2-container--classic .select2-selection--multiple .select2-selection__choice__display{cursor:default;padding-left:2px;padding-right:5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{background-color:transparent;border:none;border-top-left-radius:4px;border-bottom-left-radius:4px;color:#888;cursor:pointer;font-size:1em;font-weight:bold;padding:0 4px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555;outline:none}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__display{padding-left:5px;padding-right:2px}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:4px;border-bottom-right-radius:4px}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option--group{padding:0}.select2-container--classic .select2-results__option--disabled{color:grey}.select2-container--classic .select2-results__option--highlighted.select2-results__option--selectable{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} \ No newline at end of file diff --git a/src/main/webapp/assets/libraries/select2/js/select2.min.js b/src/main/webapp/assets/libraries/select2/js/select2.min.js new file mode 100644 index 00000000..cc9a83f1 --- /dev/null +++ b/src/main/webapp/assets/libraries/select2/js/select2.min.js @@ -0,0 +1,2 @@ +/*! Select2 4.1.0-rc.0 | https://github.com/select2/select2/blob/master/LICENSE.md */ +!function(n){"function"==typeof define&&define.amd?define(["jquery"],n):"object"==typeof module&&module.exports?module.exports=function(e,t){return void 0===t&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t),t}:n(jQuery)}(function(t){var e,n,s,p,r,o,h,f,g,m,y,v,i,a,_,s=((u=t&&t.fn&&t.fn.select2&&t.fn.select2.amd?t.fn.select2.amd:u)&&u.requirejs||(u?n=u:u={},g={},m={},y={},v={},i=Object.prototype.hasOwnProperty,a=[].slice,_=/\.js$/,h=function(e,t){var n,s,i=c(e),r=i[0],t=t[1];return e=i[1],r&&(n=x(r=l(r,t))),r?e=n&&n.normalize?n.normalize(e,(s=t,function(e){return l(e,s)})):l(e,t):(r=(i=c(e=l(e,t)))[0],e=i[1],r&&(n=x(r))),{f:r?r+"!"+e:e,n:e,pr:r,p:n}},f={require:function(e){return w(e)},exports:function(e){var t=g[e];return void 0!==t?t:g[e]={}},module:function(e){return{id:e,uri:"",exports:g[e],config:(t=e,function(){return y&&y.config&&y.config[t]||{}})};var t}},r=function(e,t,n,s){var i,r,o,a,l,c=[],u=typeof n,d=A(s=s||e);if("undefined"==u||"function"==u){for(t=!t.length&&n.length?["require","exports","module"]:t,a=0;a":">",'"':""","'":"'","/":"/"};return"string"!=typeof e?e:String(e).replace(/[&<>"'\/\\]/g,function(e){return t[e]})},s.__cache={};var n=0;return s.GetUniqueElementId=function(e){var t=e.getAttribute("data-select2-id");return null!=t||(t=e.id?"select2-data-"+e.id:"select2-data-"+(++n).toString()+"-"+s.generateChars(4),e.setAttribute("data-select2-id",t)),t},s.StoreData=function(e,t,n){e=s.GetUniqueElementId(e);s.__cache[e]||(s.__cache[e]={}),s.__cache[e][t]=n},s.GetData=function(e,t){var n=s.GetUniqueElementId(e);return t?s.__cache[n]&&null!=s.__cache[n][t]?s.__cache[n][t]:r(e).data(t):s.__cache[n]},s.RemoveData=function(e){var t=s.GetUniqueElementId(e);null!=s.__cache[t]&&delete s.__cache[t],e.removeAttribute("data-select2-id")},s.copyNonInternalCssClasses=function(e,t){var n=(n=e.getAttribute("class").trim().split(/\s+/)).filter(function(e){return 0===e.indexOf("select2-")}),t=(t=t.getAttribute("class").trim().split(/\s+/)).filter(function(e){return 0!==e.indexOf("select2-")}),t=n.concat(t);e.setAttribute("class",t.join(" "))},s}),u.define("select2/results",["jquery","./utils"],function(d,p){function s(e,t,n){this.$element=e,this.data=n,this.options=t,s.__super__.constructor.call(this)}return p.Extend(s,p.Observable),s.prototype.render=function(){var e=d('
      ');return this.options.get("multiple")&&e.attr("aria-multiselectable","true"),this.$results=e},s.prototype.clear=function(){this.$results.empty()},s.prototype.displayMessage=function(e){var t=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var n=d(''),s=this.options.get("translations").get(e.message);n.append(t(s(e.args))),n[0].className+=" select2-results__message",this.$results.append(n)},s.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},s.prototype.append=function(e){this.hideLoading();var t=[];if(null!=e.results&&0!==e.results.length){e.results=this.sort(e.results);for(var n=0;n",{class:"select2-results__options select2-results__options--nested",role:"none"});i.append(l),o.append(a),o.append(i)}else this.template(e,t);return p.StoreData(t,"data",e),t},s.prototype.bind=function(t,e){var i=this,n=t.id+"-results";this.$results.attr("id",n),t.on("results:all",function(e){i.clear(),i.append(e.data),t.isOpen()&&(i.setClasses(),i.highlightFirstItem())}),t.on("results:append",function(e){i.append(e.data),t.isOpen()&&i.setClasses()}),t.on("query",function(e){i.hideMessages(),i.showLoading(e)}),t.on("select",function(){t.isOpen()&&(i.setClasses(),i.options.get("scrollAfterSelect")&&i.highlightFirstItem())}),t.on("unselect",function(){t.isOpen()&&(i.setClasses(),i.options.get("scrollAfterSelect")&&i.highlightFirstItem())}),t.on("open",function(){i.$results.attr("aria-expanded","true"),i.$results.attr("aria-hidden","false"),i.setClasses(),i.ensureHighlightVisible()}),t.on("close",function(){i.$results.attr("aria-expanded","false"),i.$results.attr("aria-hidden","true"),i.$results.removeAttr("aria-activedescendant")}),t.on("results:toggle",function(){var e=i.getHighlightedResults();0!==e.length&&e.trigger("mouseup")}),t.on("results:select",function(){var e,t=i.getHighlightedResults();0!==t.length&&(e=p.GetData(t[0],"data"),t.hasClass("select2-results__option--selected")?i.trigger("close",{}):i.trigger("select",{data:e}))}),t.on("results:previous",function(){var e,t=i.getHighlightedResults(),n=i.$results.find(".select2-results__option--selectable"),s=n.index(t);s<=0||(e=s-1,0===t.length&&(e=0),(s=n.eq(e)).trigger("mouseenter"),t=i.$results.offset().top,n=s.offset().top,s=i.$results.scrollTop()+(n-t),0===e?i.$results.scrollTop(0):n-t<0&&i.$results.scrollTop(s))}),t.on("results:next",function(){var e,t=i.getHighlightedResults(),n=i.$results.find(".select2-results__option--selectable"),s=n.index(t)+1;s>=n.length||((e=n.eq(s)).trigger("mouseenter"),t=i.$results.offset().top+i.$results.outerHeight(!1),n=e.offset().top+e.outerHeight(!1),e=i.$results.scrollTop()+n-t,0===s?i.$results.scrollTop(0):tthis.$results.outerHeight()||s<0)&&this.$results.scrollTop(n))},s.prototype.template=function(e,t){var n=this.options.get("templateResult"),s=this.options.get("escapeMarkup"),e=n(e,t);null==e?t.style.display="none":"string"==typeof e?t.innerHTML=s(e):d(t).append(e)},s}),u.define("select2/keys",[],function(){return{BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46}}),u.define("select2/selection/base",["jquery","../utils","../keys"],function(n,s,i){function r(e,t){this.$element=e,this.options=t,r.__super__.constructor.call(this)}return s.Extend(r,s.Observable),r.prototype.render=function(){var e=n('');return this._tabindex=0,null!=s.GetData(this.$element[0],"old-tabindex")?this._tabindex=s.GetData(this.$element[0],"old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),e.attr("title",this.$element.attr("title")),e.attr("tabindex",this._tabindex),e.attr("aria-disabled","false"),this.$selection=e},r.prototype.bind=function(e,t){var n=this,s=e.id+"-results";this.container=e,this.$selection.on("focus",function(e){n.trigger("focus",e)}),this.$selection.on("blur",function(e){n._handleBlur(e)}),this.$selection.on("keydown",function(e){n.trigger("keypress",e),e.which===i.SPACE&&e.preventDefault()}),e.on("results:focus",function(e){n.$selection.attr("aria-activedescendant",e.data._resultId)}),e.on("selection:update",function(e){n.update(e.data)}),e.on("open",function(){n.$selection.attr("aria-expanded","true"),n.$selection.attr("aria-owns",s),n._attachCloseHandler(e)}),e.on("close",function(){n.$selection.attr("aria-expanded","false"),n.$selection.removeAttr("aria-activedescendant"),n.$selection.removeAttr("aria-owns"),n.$selection.trigger("focus"),n._detachCloseHandler(e)}),e.on("enable",function(){n.$selection.attr("tabindex",n._tabindex),n.$selection.attr("aria-disabled","false")}),e.on("disable",function(){n.$selection.attr("tabindex","-1"),n.$selection.attr("aria-disabled","true")})},r.prototype._handleBlur=function(e){var t=this;window.setTimeout(function(){document.activeElement==t.$selection[0]||n.contains(t.$selection[0],document.activeElement)||t.trigger("blur",e)},1)},r.prototype._attachCloseHandler=function(e){n(document.body).on("mousedown.select2."+e.id,function(e){var t=n(e.target).closest(".select2");n(".select2.select2-container--open").each(function(){this!=t[0]&&s.GetData(this,"element").select2("close")})})},r.prototype._detachCloseHandler=function(e){n(document.body).off("mousedown.select2."+e.id)},r.prototype.position=function(e,t){t.find(".selection").append(e)},r.prototype.destroy=function(){this._detachCloseHandler(this.container)},r.prototype.update=function(e){throw new Error("The `update` method must be defined in child classes.")},r.prototype.isEnabled=function(){return!this.isDisabled()},r.prototype.isDisabled=function(){return this.options.get("disabled")},r}),u.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(e,t,n,s){function i(){i.__super__.constructor.apply(this,arguments)}return n.Extend(i,t),i.prototype.render=function(){var e=i.__super__.render.call(this);return e[0].classList.add("select2-selection--single"),e.html(''),e},i.prototype.bind=function(t,e){var n=this;i.__super__.bind.apply(this,arguments);var s=t.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",s).attr("role","textbox").attr("aria-readonly","true"),this.$selection.attr("aria-labelledby",s),this.$selection.attr("aria-controls",s),this.$selection.on("mousedown",function(e){1===e.which&&n.trigger("toggle",{originalEvent:e})}),this.$selection.on("focus",function(e){}),this.$selection.on("blur",function(e){}),t.on("focus",function(e){t.isOpen()||n.$selection.trigger("focus")})},i.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},i.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},i.prototype.selectionContainer=function(){return e("")},i.prototype.update=function(e){var t,n;0!==e.length?(n=e[0],t=this.$selection.find(".select2-selection__rendered"),e=this.display(n,t),t.empty().append(e),(n=n.title||n.text)?t.attr("title",n):t.removeAttr("title")):this.clear()},i}),u.define("select2/selection/multiple",["jquery","./base","../utils"],function(i,e,c){function r(e,t){r.__super__.constructor.apply(this,arguments)}return c.Extend(r,e),r.prototype.render=function(){var e=r.__super__.render.call(this);return e[0].classList.add("select2-selection--multiple"),e.html('
        '),e},r.prototype.bind=function(e,t){var n=this;r.__super__.bind.apply(this,arguments);var s=e.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",s),this.$selection.on("click",function(e){n.trigger("toggle",{originalEvent:e})}),this.$selection.on("click",".select2-selection__choice__remove",function(e){var t;n.isDisabled()||(t=i(this).parent(),t=c.GetData(t[0],"data"),n.trigger("unselect",{originalEvent:e,data:t}))}),this.$selection.on("keydown",".select2-selection__choice__remove",function(e){n.isDisabled()||e.stopPropagation()})},r.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},r.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},r.prototype.selectionContainer=function(){return i('
      • ')},r.prototype.update=function(e){if(this.clear(),0!==e.length){for(var t=[],n=this.$selection.find(".select2-selection__rendered").attr("id")+"-choice-",s=0;s')).attr("title",s()),e.attr("aria-label",s()),e.attr("aria-describedby",n),a.StoreData(e[0],"data",t),this.$selection.prepend(e),this.$selection[0].classList.add("select2-selection--clearable"))},e}),u.define("select2/selection/search",["jquery","../utils","../keys"],function(s,a,l){function e(e,t,n){e.call(this,t,n)}return e.prototype.render=function(e){var t=this.options.get("translations").get("search"),n=s('');this.$searchContainer=n,this.$search=n.find("textarea"),this.$search.prop("autocomplete",this.options.get("autocomplete")),this.$search.attr("aria-label",t());e=e.call(this);return this._transferTabIndex(),e.append(this.$searchContainer),e},e.prototype.bind=function(e,t,n){var s=this,i=t.id+"-results",r=t.id+"-container";e.call(this,t,n),s.$search.attr("aria-describedby",r),t.on("open",function(){s.$search.attr("aria-controls",i),s.$search.trigger("focus")}),t.on("close",function(){s.$search.val(""),s.resizeSearch(),s.$search.removeAttr("aria-controls"),s.$search.removeAttr("aria-activedescendant"),s.$search.trigger("focus")}),t.on("enable",function(){s.$search.prop("disabled",!1),s._transferTabIndex()}),t.on("disable",function(){s.$search.prop("disabled",!0)}),t.on("focus",function(e){s.$search.trigger("focus")}),t.on("results:focus",function(e){e.data._resultId?s.$search.attr("aria-activedescendant",e.data._resultId):s.$search.removeAttr("aria-activedescendant")}),this.$selection.on("focusin",".select2-search--inline",function(e){s.trigger("focus",e)}),this.$selection.on("focusout",".select2-search--inline",function(e){s._handleBlur(e)}),this.$selection.on("keydown",".select2-search--inline",function(e){var t;e.stopPropagation(),s.trigger("keypress",e),s._keyUpPrevented=e.isDefaultPrevented(),e.which!==l.BACKSPACE||""!==s.$search.val()||0<(t=s.$selection.find(".select2-selection__choice").last()).length&&(t=a.GetData(t[0],"data"),s.searchRemoveChoice(t),e.preventDefault())}),this.$selection.on("click",".select2-search--inline",function(e){s.$search.val()&&e.stopPropagation()});var t=document.documentMode,o=t&&t<=11;this.$selection.on("input.searchcheck",".select2-search--inline",function(e){o?s.$selection.off("input.search input.searchcheck"):s.$selection.off("keyup.search")}),this.$selection.on("keyup.search input.search",".select2-search--inline",function(e){var t;o&&"input"===e.type?s.$selection.off("input.search input.searchcheck"):(t=e.which)!=l.SHIFT&&t!=l.CTRL&&t!=l.ALT&&t!=l.TAB&&s.handleSearch(e)})},e.prototype._transferTabIndex=function(e){this.$search.attr("tabindex",this.$selection.attr("tabindex")),this.$selection.attr("tabindex","-1")},e.prototype.createPlaceholder=function(e,t){this.$search.attr("placeholder",t.text)},e.prototype.update=function(e,t){var n=this.$search[0]==document.activeElement;this.$search.attr("placeholder",""),e.call(this,t),this.resizeSearch(),n&&this.$search.trigger("focus")},e.prototype.handleSearch=function(){var e;this.resizeSearch(),this._keyUpPrevented||(e=this.$search.val(),this.trigger("query",{term:e})),this._keyUpPrevented=!1},e.prototype.searchRemoveChoice=function(e,t){this.trigger("unselect",{data:t}),this.$search.val(t.text),this.handleSearch()},e.prototype.resizeSearch=function(){this.$search.css("width","25px");var e="100%";""===this.$search.attr("placeholder")&&(e=.75*(this.$search.val().length+1)+"em"),this.$search.css("width",e)},e}),u.define("select2/selection/selectionCss",["../utils"],function(n){function e(){}return e.prototype.render=function(e){var t=e.call(this),e=this.options.get("selectionCssClass")||"";return-1!==e.indexOf(":all:")&&(e=e.replace(":all:",""),n.copyNonInternalCssClasses(t[0],this.$element[0])),t.addClass(e),t},e}),u.define("select2/selection/eventRelay",["jquery"],function(o){function e(){}return e.prototype.bind=function(e,t,n){var s=this,i=["open","opening","close","closing","select","selecting","unselect","unselecting","clear","clearing"],r=["opening","closing","selecting","unselecting","clearing"];e.call(this,t,n),t.on("*",function(e,t){var n;-1!==i.indexOf(e)&&(t=t||{},n=o.Event("select2:"+e,{params:t}),s.$element.trigger(n),-1!==r.indexOf(e)&&(t.prevented=n.isDefaultPrevented()))})},e}),u.define("select2/translation",["jquery","require"],function(t,n){function s(e){this.dict=e||{}}return s.prototype.all=function(){return this.dict},s.prototype.get=function(e){return this.dict[e]},s.prototype.extend=function(e){this.dict=t.extend({},e.all(),this.dict)},s._cache={},s.loadPath=function(e){var t;return e in s._cache||(t=n(e),s._cache[e]=t),new s(s._cache[e])},s}),u.define("select2/diacritics",[],function(){return{"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Œ":"OE","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","œ":"oe","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ώ":"ω","ς":"σ","’":"'"}}),u.define("select2/data/base",["../utils"],function(n){function s(e,t){s.__super__.constructor.call(this)}return n.Extend(s,n.Observable),s.prototype.current=function(e){throw new Error("The `current` method must be defined in child classes.")},s.prototype.query=function(e,t){throw new Error("The `query` method must be defined in child classes.")},s.prototype.bind=function(e,t){},s.prototype.destroy=function(){},s.prototype.generateResultId=function(e,t){e=e.id+"-result-";return e+=n.generateChars(4),null!=t.id?e+="-"+t.id.toString():e+="-"+n.generateChars(4),e},s}),u.define("select2/data/select",["./base","../utils","jquery"],function(e,a,l){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return a.Extend(n,e),n.prototype.current=function(e){var t=this;e(Array.prototype.map.call(this.$element[0].querySelectorAll(":checked"),function(e){return t.item(l(e))}))},n.prototype.select=function(i){var e,r=this;if(i.selected=!0,null!=i.element&&"option"===i.element.tagName.toLowerCase())return i.element.selected=!0,void this.$element.trigger("input").trigger("change");this.$element.prop("multiple")?this.current(function(e){var t=[];(i=[i]).push.apply(i,e);for(var n=0;nthis.maximumInputLength?this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:t.term,params:t}}):e.call(this,t,n)},e}),u.define("select2/data/maximumSelectionLength",[],function(){function e(e,t,n){this.maximumSelectionLength=n.get("maximumSelectionLength"),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var s=this;e.call(this,t,n),t.on("select",function(){s._checkIfMaximumSelected()})},e.prototype.query=function(e,t,n){var s=this;this._checkIfMaximumSelected(function(){e.call(s,t,n)})},e.prototype._checkIfMaximumSelected=function(e,t){var n=this;this.current(function(e){e=null!=e?e.length:0;0=n.maximumSelectionLength?n.trigger("results:message",{message:"maximumSelected",args:{maximum:n.maximumSelectionLength}}):t&&t()})},e}),u.define("select2/dropdown",["jquery","./utils"],function(t,e){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return e.Extend(n,e.Observable),n.prototype.render=function(){var e=t('');return e.attr("dir",this.options.get("dir")),this.$dropdown=e},n.prototype.bind=function(){},n.prototype.position=function(e,t){},n.prototype.destroy=function(){this.$dropdown.remove()},n}),u.define("select2/dropdown/search",["jquery"],function(r){function e(){}return e.prototype.render=function(e){var t=e.call(this),n=this.options.get("translations").get("search"),e=r('');return this.$searchContainer=e,this.$search=e.find("input"),this.$search.prop("autocomplete",this.options.get("autocomplete")),this.$search.attr("aria-label",n()),t.prepend(e),t},e.prototype.bind=function(e,t,n){var s=this,i=t.id+"-results";e.call(this,t,n),this.$search.on("keydown",function(e){s.trigger("keypress",e),s._keyUpPrevented=e.isDefaultPrevented()}),this.$search.on("input",function(e){r(this).off("keyup")}),this.$search.on("keyup input",function(e){s.handleSearch(e)}),t.on("open",function(){s.$search.attr("tabindex",0),s.$search.attr("aria-controls",i),s.$search.trigger("focus"),window.setTimeout(function(){s.$search.trigger("focus")},0)}),t.on("close",function(){s.$search.attr("tabindex",-1),s.$search.removeAttr("aria-controls"),s.$search.removeAttr("aria-activedescendant"),s.$search.val(""),s.$search.trigger("blur")}),t.on("focus",function(){t.isOpen()||s.$search.trigger("focus")}),t.on("results:all",function(e){null!=e.query.term&&""!==e.query.term||(s.showSearch(e)?s.$searchContainer[0].classList.remove("select2-search--hide"):s.$searchContainer[0].classList.add("select2-search--hide"))}),t.on("results:focus",function(e){e.data._resultId?s.$search.attr("aria-activedescendant",e.data._resultId):s.$search.removeAttr("aria-activedescendant")})},e.prototype.handleSearch=function(e){var t;this._keyUpPrevented||(t=this.$search.val(),this.trigger("query",{term:t})),this._keyUpPrevented=!1},e.prototype.showSearch=function(e,t){return!0},e}),u.define("select2/dropdown/hidePlaceholder",[],function(){function e(e,t,n,s){this.placeholder=this.normalizePlaceholder(n.get("placeholder")),e.call(this,t,n,s)}return e.prototype.append=function(e,t){t.results=this.removePlaceholder(t.results),e.call(this,t)},e.prototype.normalizePlaceholder=function(e,t){return t="string"==typeof t?{id:"",text:t}:t},e.prototype.removePlaceholder=function(e,t){for(var n=t.slice(0),s=t.length-1;0<=s;s--){var i=t[s];this.placeholder.id===i.id&&n.splice(s,1)}return n},e}),u.define("select2/dropdown/infiniteScroll",["jquery"],function(n){function e(e,t,n,s){this.lastParams={},e.call(this,t,n,s),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return e.prototype.append=function(e,t){this.$loadingMore.remove(),this.loading=!1,e.call(this,t),this.showLoadingMore(t)&&(this.$results.append(this.$loadingMore),this.loadMoreIfNeeded())},e.prototype.bind=function(e,t,n){var s=this;e.call(this,t,n),t.on("query",function(e){s.lastParams=e,s.loading=!0}),t.on("query:append",function(e){s.lastParams=e,s.loading=!0}),this.$results.on("scroll",this.loadMoreIfNeeded.bind(this))},e.prototype.loadMoreIfNeeded=function(){var e=n.contains(document.documentElement,this.$loadingMore[0]);!this.loading&&e&&(e=this.$results.offset().top+this.$results.outerHeight(!1),this.$loadingMore.offset().top+this.$loadingMore.outerHeight(!1)<=e+50&&this.loadMore())},e.prototype.loadMore=function(){this.loading=!0;var e=n.extend({},{page:1},this.lastParams);e.page++,this.trigger("query:append",e)},e.prototype.showLoadingMore=function(e,t){return t.pagination&&t.pagination.more},e.prototype.createLoadingMore=function(){var e=n('
      • '),t=this.options.get("translations").get("loadingMore");return e.html(t(this.lastParams)),e},e}),u.define("select2/dropdown/attachBody",["jquery","../utils"],function(u,o){function e(e,t,n){this.$dropdownParent=u(n.get("dropdownParent")||document.body),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var s=this;e.call(this,t,n),t.on("open",function(){s._showDropdown(),s._attachPositioningHandler(t),s._bindContainerResultHandlers(t)}),t.on("close",function(){s._hideDropdown(),s._detachPositioningHandler(t)}),this.$dropdownContainer.on("mousedown",function(e){e.stopPropagation()})},e.prototype.destroy=function(e){e.call(this),this.$dropdownContainer.remove()},e.prototype.position=function(e,t,n){t.attr("class",n.attr("class")),t[0].classList.remove("select2"),t[0].classList.add("select2-container--open"),t.css({position:"absolute",top:-999999}),this.$container=n},e.prototype.render=function(e){var t=u(""),e=e.call(this);return t.append(e),this.$dropdownContainer=t},e.prototype._hideDropdown=function(e){this.$dropdownContainer.detach()},e.prototype._bindContainerResultHandlers=function(e,t){var n;this._containerResultsHandlersBound||(n=this,t.on("results:all",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:append",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:message",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("select",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("unselect",function(){n._positionDropdown(),n._resizeDropdown()}),this._containerResultsHandlersBound=!0)},e.prototype._attachPositioningHandler=function(e,t){var n=this,s="scroll.select2."+t.id,i="resize.select2."+t.id,r="orientationchange.select2."+t.id,t=this.$container.parents().filter(o.hasScroll);t.each(function(){o.StoreData(this,"select2-scroll-position",{x:u(this).scrollLeft(),y:u(this).scrollTop()})}),t.on(s,function(e){var t=o.GetData(this,"select2-scroll-position");u(this).scrollTop(t.y)}),u(window).on(s+" "+i+" "+r,function(e){n._positionDropdown(),n._resizeDropdown()})},e.prototype._detachPositioningHandler=function(e,t){var n="scroll.select2."+t.id,s="resize.select2."+t.id,t="orientationchange.select2."+t.id;this.$container.parents().filter(o.hasScroll).off(n),u(window).off(n+" "+s+" "+t)},e.prototype._positionDropdown=function(){var e=u(window),t=this.$dropdown[0].classList.contains("select2-dropdown--above"),n=this.$dropdown[0].classList.contains("select2-dropdown--below"),s=null,i=this.$container.offset();i.bottom=i.top+this.$container.outerHeight(!1);var r={height:this.$container.outerHeight(!1)};r.top=i.top,r.bottom=i.top+r.height;var o=this.$dropdown.outerHeight(!1),a=e.scrollTop(),l=e.scrollTop()+e.height(),c=ai.bottom+o,a={left:i.left,top:r.bottom},l=this.$dropdownParent;"static"===l.css("position")&&(l=l.offsetParent());i={top:0,left:0};(u.contains(document.body,l[0])||l[0].isConnected)&&(i=l.offset()),a.top-=i.top,a.left-=i.left,t||n||(s="below"),e||!c||t?!c&&e&&t&&(s="below"):s="above",("above"==s||t&&"below"!==s)&&(a.top=r.top-i.top-o),null!=s&&(this.$dropdown[0].classList.remove("select2-dropdown--below"),this.$dropdown[0].classList.remove("select2-dropdown--above"),this.$dropdown[0].classList.add("select2-dropdown--"+s),this.$container[0].classList.remove("select2-container--below"),this.$container[0].classList.remove("select2-container--above"),this.$container[0].classList.add("select2-container--"+s)),this.$dropdownContainer.css(a)},e.prototype._resizeDropdown=function(){var e={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(e.minWidth=e.width,e.position="relative",e.width="auto"),this.$dropdown.css(e)},e.prototype._showDropdown=function(e){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},e}),u.define("select2/dropdown/minimumResultsForSearch",[],function(){function e(e,t,n,s){this.minimumResultsForSearch=n.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),e.call(this,t,n,s)}return e.prototype.showSearch=function(e,t){return!(function e(t){for(var n=0,s=0;s');return e.attr("dir",this.options.get("dir")),this.$container=e,this.$container[0].classList.add("select2-container--"+this.options.get("theme")),r.StoreData(e[0],"element",this.$element),e},o}),u.define("jquery-mousewheel",["jquery"],function(e){return e}),u.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults","./select2/utils"],function(i,e,r,t,o){var a;return null==i.fn.select2&&(a=["open","close","destroy"],i.fn.select2=function(t){if("object"==typeof(t=t||{}))return this.each(function(){var e=i.extend(!0,{},t);new r(i(this),e)}),this;if("string"!=typeof t)throw new Error("Invalid arguments for Select2: "+t);var n,s=Array.prototype.slice.call(arguments,1);return this.each(function(){var e=o.GetData(this,"select2");null==e&&window.console&&console.error&&console.error("The select2('"+t+"') method was called on an element that is not using Select2."),n=e[t].apply(e,s)}),-1 Date: Fri, 15 Mar 2024 19:56:48 -0300 Subject: [PATCH 7/9] descriptive search --- .../controller/IndexController.java | 43 +++- .../controller/JobRequestController.java | 15 +- src/main/webapp/WEB-INF/tags/search-bar.tag | 23 +- .../client/job-request/wizard-step-08.jsp | 79 +++++- .../WEB-INF/view/visitor/search-results.jsp | 7 + .../webapp/assets/resources/scripts/main.js | 238 +++++++++--------- .../webapp/assets/resources/scripts/search.js | 121 +++++++++ 7 files changed, 383 insertions(+), 143 deletions(-) create mode 100644 src/main/webapp/assets/resources/scripts/search.js diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/IndexController.java b/src/main/java/br/edu/utfpr/servicebook/controller/IndexController.java index 922385d1..49b3bd06 100644 --- a/src/main/java/br/edu/utfpr/servicebook/controller/IndexController.java +++ b/src/main/java/br/edu/utfpr/servicebook/controller/IndexController.java @@ -150,32 +150,49 @@ public String notAuthorized() { @PermitAll @ResponseBody public List showExpertisesByCategory(@PathVariable Long categoryId) throws Exception { - Optional oCategory = categoryService.findById(categoryId); + if(categoryId != null){ + List expertises = expertiseService.findByCategoryId(categoryId); - Category category = categoryService.findById(categoryId).orElseThrow(() -> new EntityNotFoundException("Categoria não encontrada")); + List expertiseDTOS = expertises.stream() + .map(s -> expertiseMapper.toDto(s)) + .collect(Collectors.toList()); - List expertises = expertiseService.findByCategoryId(categoryId); + return expertiseDTOS; + } else { + List expertises = expertiseService.findAll(); - List expertiseDTOS = expertises.stream() - .map(s -> expertiseMapper.toDto(s)) - .collect(Collectors.toList()); + List expertiseDTOS = expertises.stream() + .map(s -> expertiseMapper.toDto(s)) + .collect(Collectors.toList()); + + return expertiseDTOS; + } - return expertiseDTOS; } @GetMapping("/servicos/especialidade/{expertiseId}") @PermitAll @ResponseBody public List showServicesByExpertise(@PathVariable Long expertiseId) throws Exception { + if(expertiseId != null){ + Expertise expertise = expertiseService.findById(expertiseId).orElseThrow(() -> new EntityNotFoundException("Especialidade não encontrada")); - Expertise expertise = expertiseService.findById(expertiseId).orElseThrow(() -> new EntityNotFoundException("Especialidade não encontrada")); + List services = serviceService.findByExpertise(expertise); - List services = serviceService.findByExpertise(expertise); + List servicesDTO = services.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); + return servicesDTO; - List servicesDTO = services.stream() - .map(s -> serviceMapper.toDto(s)) - .collect(Collectors.toList()); + } else { + List services = serviceService.findAll(); + + List servicesDTO = services.stream() + .map(s -> serviceMapper.toDto(s)) + .collect(Collectors.toList()); + + return servicesDTO; + } - return servicesDTO; } } \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/JobRequestController.java b/src/main/java/br/edu/utfpr/servicebook/controller/JobRequestController.java index 00f8f6b7..3f7fd2e2 100644 --- a/src/main/java/br/edu/utfpr/servicebook/controller/JobRequestController.java +++ b/src/main/java/br/edu/utfpr/servicebook/controller/JobRequestController.java @@ -22,6 +22,7 @@ import com.cloudinary.utils.ObjectUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; @@ -121,6 +122,14 @@ public String showWizard(@RequestParam(value = "passo", required = false, defaul if(step < 1 || step > 8){ step = 1L; } + + String currentUserEmail = authentication.getEmail(); + + Optional oUser = userService.findByEmail(currentUserEmail); +// if (!oUser.isPresent()) { +// return "redirect:/login"; +// } + JobRequestDTO dto = wizardSessionUtil.getWizardState(httpSession, JobRequestDTO.class, WizardSessionUtil.KEY_WIZARD_JOB_REQUEST); model.addAttribute("dto", dto); @@ -291,7 +300,7 @@ public String saveFormImagePath(HttpSession httpSession, RedirectAttributes redi sessionDTO.setImageSession((String)data.get("url")); log.debug("Passo 5 {}", sessionDTO); - return "redirect:/requisicoes/passo=5"; + return "redirect:/requisicoes?passo=8"; } else { return "redirect:/requisicoes/passo=5"; } @@ -336,7 +345,7 @@ public String saveFormVerification(HttpSession httpSession, JobRequestDTO dto, R User user = null; Optional oUser = userService.findByEmail(authentication.getEmail()); if(oUser.isPresent()){ - user = oUser.get(); + user = oUser.get(); } Expertise exp = oExpertise.get(); @@ -456,4 +465,4 @@ public String rememberToHide(@PathVariable Long id, RedirectAttributes redirectA return "redirect:/minha-conta/profissional#disponiveis"; } -} +} \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/tags/search-bar.tag b/src/main/webapp/WEB-INF/tags/search-bar.tag index 7ab5471e..73c02df0 100644 --- a/src/main/webapp/WEB-INF/tags/search-bar.tag +++ b/src/main/webapp/WEB-INF/tags/search-bar.tag @@ -9,7 +9,9 @@ crossorigin="anonymous">
        -
        + + +

        O QUE VOCÊ PRECISA?

        @@ -61,7 +63,7 @@
        -
        @@ -69,4 +71,21 @@
        + + + +
        +
        +
        +

        O QUE VOCÊ PRECISA?

        +
        Crie um anúncio da sua solicitação para facilitar a comunicação com os profissionais.
        +
        Você descreve apenas uma vez e compartilha com os profissionais.
        + BUSCA DESCRITIVA +
        + +
        +
        +
        +
        + diff --git a/src/main/webapp/WEB-INF/view/client/job-request/wizard-step-08.jsp b/src/main/webapp/WEB-INF/view/client/job-request/wizard-step-08.jsp index d2b305ae..53fc818c 100644 --- a/src/main/webapp/WEB-INF/view/client/job-request/wizard-step-08.jsp +++ b/src/main/webapp/WEB-INF/view/client/job-request/wizard-step-08.jsp @@ -14,16 +14,83 @@
        +
        -
        -

        Olá João, recebemos a sua solicitação de serviço!

        -

        Fique atento, logo você começará a receber os contatos dos profissionais interessados em realizar o serviço no prazo especificado!

        -
        -
        - Acompanhe a sua solicitação +
        +

        Estes ${professionalsAmount} profissionais tem a especialidade que procura!

        +
        Para ter acesso a lista completa de profissionais deste especialidade ou melhor, para receber o contato de apenas profissionais interessados e disponíveis para a data especificada, podendo você verificar a reputação dos mesmos e experiência, solicitar orçamento e por fim, avaliar o serviço prestado.
        +
        +
        +
        +
        +
        + + +
        +
        +
        +
        + + + Foto de perfil + + + Sem foto de perfil + + +
        +
        +
        ${professional.name}
        +
        +
        +
        + +
        ${expertise.name}
        +
        +
        +
        + +
        +
        +
        +
        + +
        +
        +
        +
        + sentiment_dissatisfied +

        + Nenhum profissional encontrado! +

        +
        +
        +
        +
        +
        +
        +
        +
        + +
        +
        +

        LOGIN PARA EFETIVAR O SEU PEDIDO E RECEBER OS CONTATOS DOS PROFISSIONAIS!

        + Entrar +
        + +
        + +
        +

        VOCÊ AINDA NÃO TEM UMA CONTA?

        + Cadastrar-se +
        +
        +
        diff --git a/src/main/webapp/WEB-INF/view/visitor/search-results.jsp b/src/main/webapp/WEB-INF/view/visitor/search-results.jsp index 6228f15e..9be5a209 100644 --- a/src/main/webapp/WEB-INF/view/visitor/search-results.jsp +++ b/src/main/webapp/WEB-INF/view/visitor/search-results.jsp @@ -100,8 +100,15 @@ + diff --git a/src/main/webapp/assets/resources/scripts/main.js b/src/main/webapp/assets/resources/scripts/main.js index 193cdaf3..b46be59e 100644 --- a/src/main/webapp/assets/resources/scripts/main.js +++ b/src/main/webapp/assets/resources/scripts/main.js @@ -31,123 +31,123 @@ $(document).ready(function () { } }); - if ($("#category-select").val() != '') { - selectCategory($("#category-select").val()) - } - - var element = $("#dto_expertise").val(); - - function selectCategory(categoryId) { - $.ajax({ - url: "especialidades/categoria/"+ categoryId, - type: "GET", - success: function (expertises) { - $("#expertise-select").empty(); - - //se o array for vazio, coloca o option que não há especialidades - if (expertises.length === 0){ - $('#expertise-select').prop("disabled", true); - $("#expertise-select").append(""); - } else - $('#expertise-select').removeAttr("disabled"); - $("#expertise-select").append(""); - - $.each(expertises, function (index, expertise) { - - if(expertise.id == element){ - $("#expertise-select").append(""); - }else { - $("#expertise-select").append(""); - } - - }); - $("#expertise-select").formSelect(); - } - }); - } - if ($("#expertise-select").val() != '') { - selectExpertise(element) - } - - var element_service = $("#dto_service").val(); - function selectExpertise(expertiseId) { - $.ajax({ - url: "servicos/especialidade/"+ expertiseId, - type: "GET", - success: function (services) { - - $("#service-select").empty(); - - //se o array for vazio, coloca o option que não há especialidades - if (services.length === 0) { - $('#service-select').prop("disabled", true); - $("#service-select").append(""); - } else - $('#service-select').removeAttr("disabled"); - $("#service-select").append(""); - - $.each(services, function (index, service) { - $("#service-select").append(""); - - if(service.id == element_service){ - $("#service-select").append(""); - }else { - $("#service-select").append(""); - } - - }); - $("#service-select").formSelect(); - } - }); - } - - // LISTA DE ESPECIALIDADE DE ACORDO COM A CATEGORIA - $("#category-select").change(function () { - let categoryId = $(this).val(); - $.ajax({ - url: "especialidades/categoria/"+ categoryId, - type: "GET", - success: function (expertises) { - console.log(expertises) - - $("#expertise-select").empty(); - - //se o array for vazio, coloca o option que não há especialidades - if (expertises.length === 0) - $("#expertise-select").append(""); - else - $("#expertise-select").append(""); - - $.each(expertises, function (index, expertise) { - $("#expertise-select").append(""); - }); - $("#expertise-select").formSelect(); - } - }); - }); - - // LISTA DE SERVIÇOS DE ACORDO COM A ESPECIALIDADE - $("#expertise-select").change(function () { - let expertiseId = $(this).val(); - $.ajax({ - url: "servicos/especialidade/"+ expertiseId, - type: "GET", - success: function (services) { - - $("#service-select").empty(); - - //se o array for vazio, coloca o option que não há especialidades - if (services.length === 0) - $("#service-select").append(""); - else - $("#service-select").append(""); - - $.each(services, function (index, service) { - $("#service-select").append(""); - - }); - $("#service-select").formSelect(); - } - }); - }); + // if ($("#category-select").val() != '') { + // selectCategory($("#category-select").val()) + // } + // + // var element = $("#dto_expertise").val(); + // + // function selectCategory(categoryId) { + // $.ajax({ + // url: "especialidades/categoria/"+ categoryId, + // type: "GET", + // success: function (expertises) { + // $("#expertise-select").empty(); + // + // //se o array for vazio, coloca o option que não há especialidades + // if (expertises.length === 0){ + // $('#expertise-select').prop("disabled", true); + // $("#expertise-select").append(""); + // } else + // $('#expertise-select').removeAttr("disabled"); + // $("#expertise-select").append(""); + // + // $.each(expertises, function (index, expertise) { + // + // if(expertise.id == element){ + // $("#expertise-select").append(""); + // }else { + // $("#expertise-select").append(""); + // } + // + // }); + // $("#expertise-select").formSelect(); + // } + // }); + // } + // if ($("#expertise-select").val() != '') { + // selectExpertise(element) + // } + // + // var element_service = $("#dto_service").val(); + // function selectExpertise(expertiseId) { + // $.ajax({ + // url: "servicos/especialidade/"+ expertiseId, + // type: "GET", + // success: function (services) { + // + // $("#service-select").empty(); + // + // //se o array for vazio, coloca o option que não há especialidades + // if (services.length === 0) { + // $('#service-select').prop("disabled", true); + // $("#service-select").append(""); + // } else + // $('#service-select').removeAttr("disabled"); + // $("#service-select").append(""); + // + // $.each(services, function (index, service) { + // $("#service-select").append(""); + // + // if(service.id == element_service){ + // $("#service-select").append(""); + // }else { + // $("#service-select").append(""); + // } + // + // }); + // $("#service-select").formSelect(); + // } + // }); + // } + // + // // LISTA DE ESPECIALIDADE DE ACORDO COM A CATEGORIA + // $("#category-select").change(function () { + // let categoryId = $(this).val(); + // $.ajax({ + // url: "especialidades/categoria/"+ categoryId, + // type: "GET", + // success: function (expertises) { + // console.log(expertises) + // + // $("#expertise-select").empty(); + // + // //se o array for vazio, coloca o option que não há especialidades + // if (expertises.length === 0) + // $("#expertise-select").append(""); + // else + // $("#expertise-select").append(""); + // + // $.each(expertises, function (index, expertise) { + // $("#expertise-select").append(""); + // }); + // $("#expertise-select").formSelect(); + // } + // }); + // }); + // + // // LISTA DE SERVIÇOS DE ACORDO COM A ESPECIALIDADE + // $("#expertise-select").change(function () { + // let expertiseId = $(this).val(); + // $.ajax({ + // url: "servicos/especialidade/"+ expertiseId, + // type: "GET", + // success: function (services) { + // + // $("#service-select").empty(); + // + // //se o array for vazio, coloca o option que não há especialidades + // if (services.length === 0) + // $("#service-select").append(""); + // else + // $("#service-select").append(""); + // + // $.each(services, function (index, service) { + // $("#service-select").append(""); + // + // }); + // $("#service-select").formSelect(); + // } + // }); + // }); }) \ No newline at end of file diff --git a/src/main/webapp/assets/resources/scripts/search.js b/src/main/webapp/assets/resources/scripts/search.js new file mode 100644 index 00000000..4c172eae --- /dev/null +++ b/src/main/webapp/assets/resources/scripts/search.js @@ -0,0 +1,121 @@ +$(document).ready(function () { + if ($("#category-select").val() != '') { + selectCategory($("#category-select").val()) + } + + var element = $("#dto_expertise").val(); + + function selectCategory(categoryId) { + $.ajax({ + url: "especialidades/categoria/"+ categoryId, + type: "GET", + success: function (expertises) { + $("#expertise-select").empty(); + + //se o array for vazio, coloca o option que não há especialidades + if (expertises.length === 0){ + $('#expertise-select').prop("disabled", true); + $("#expertise-select").append(""); + } else + $('#expertise-select').removeAttr("disabled"); + $("#expertise-select").append(""); + + $.each(expertises, function (index, expertise) { + + if(expertise.id == element){ + $("#expertise-select").append(""); + }else { + $("#expertise-select").append(""); + } + + }); + $("#expertise-select").formSelect(); + } + }); + } + if ($("#expertise-select").val() != '') { + selectExpertise(element) + } + + var element_service = $("#dto_service").val(); + function selectExpertise(expertiseId) { + $.ajax({ + url: "servicos/especialidade/"+ expertiseId, + type: "GET", + success: function (services) { + + $("#service-select").empty(); + + //se o array for vazio, coloca o option que não há especialidades + if (services.length === 0) { + $('#service-select').prop("disabled", true); + $("#service-select").append(""); + } else + $('#service-select').removeAttr("disabled"); + $("#service-select").append(""); + + $.each(services, function (index, service) { + $("#service-select").append(""); + + if(service.id == element_service){ + $("#service-select").append(""); + }else { + $("#service-select").append(""); + } + + }); + $("#service-select").formSelect(); + } + }); + } + + // LISTA DE ESPECIALIDADE DE ACORDO COM A CATEGORIA + $("#category-select").change(function () { + let categoryId = $(this).val(); + $.ajax({ + url: "especialidades/categoria/"+ categoryId, + type: "GET", + success: function (expertises) { + console.log(expertises) + + $("#expertise-select").empty(); + + //se o array for vazio, coloca o option que não há especialidades + if (expertises.length === 0) + $("#expertise-select").append(""); + else + $("#expertise-select").append(""); + + $.each(expertises, function (index, expertise) { + $("#expertise-select").append(""); + }); + $("#expertise-select").formSelect(); + } + }); + }); + + // LISTA DE SERVIÇOS DE ACORDO COM A ESPECIALIDADE + $("#expertise-select").change(function () { + let expertiseId = $(this).val(); + $.ajax({ + url: "servicos/especialidade/"+ expertiseId, + type: "GET", + success: function (services) { + + $("#service-select").empty(); + + //se o array for vazio, coloca o option que não há especialidades + if (services.length === 0) + $("#service-select").append(""); + else + $("#service-select").append(""); + + $.each(services, function (index, service) { + $("#service-select").append(""); + + }); + $("#service-select").formSelect(); + } + }); + }); +}) \ No newline at end of file From fd4f9171d902e7cb2454396c60bb13c975b3644a Mon Sep 17 00:00:00 2001 From: TaisHryssai Date: Mon, 1 Apr 2024 20:00:34 -0300 Subject: [PATCH 8/9] =?UTF-8?q?Pagamento=20de=20servi=C3=A7o,=20utilizando?= =?UTF-8?q?=20api=20mercadoPago?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 + .../controller/ClientController.java | 150 +++++++++++++++++- .../servicebook/jobs/SendEmailVoucher.java | 72 +++++++++ .../servicebook/model/dto/PaymentDTO.java | 18 +++ .../servicebook/model/dto/PaymentJobDTO.java | 14 ++ .../model/dto/PaymentVoucherDTO.java | 22 +++ .../servicebook/model/entity/Payment.java | 31 ++++ .../model/entity/PaymentJobRequest.java | 32 ++++ .../model/entity/PaymentVoucher.java | 32 ++++ .../model/mapper/PaymentJobMapper.java | 24 +++ .../model/mapper/PaymentMapper.java | 27 ++++ .../model/mapper/PaymentVoucherMapper.java | 24 +++ .../repository/PaymentJobRepository.java | 22 +++ .../model/repository/PaymentRepository.java | 13 ++ .../repository/PaymentVoucherRepository.java | 22 +++ .../service/PaymentJobService.java | 32 ++++ .../servicebook/service/PaymentService.java | 53 +++++++ .../service/PaymentVoucherService.java | 29 ++++ .../servicebook/service/QuartzService.java | 26 +++ .../WEB-INF/view/client/details-request.jsp | 28 ++++ .../assets/resources/scripts/mp-payment.js | 145 +++++++++++++++++ 21 files changed, 819 insertions(+), 2 deletions(-) create mode 100644 src/main/java/br/edu/utfpr/servicebook/jobs/SendEmailVoucher.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentDTO.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentJobDTO.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentVoucherDTO.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/entity/Payment.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/entity/PaymentJobRequest.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/entity/PaymentVoucher.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentJobMapper.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentMapper.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentVoucherMapper.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentJobRepository.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentRepository.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentVoucherRepository.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/service/PaymentJobService.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/service/PaymentService.java create mode 100644 src/main/java/br/edu/utfpr/servicebook/service/PaymentVoucherService.java create mode 100644 src/main/webapp/assets/resources/scripts/mp-payment.js diff --git a/pom.xml b/pom.xml index 99cf0888..8a282ae3 100644 --- a/pom.xml +++ b/pom.xml @@ -139,6 +139,11 @@ jackson-databind 2.13.0 + + org.projectlombok + lombok + 1.18.24 + diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/ClientController.java b/src/main/java/br/edu/utfpr/servicebook/controller/ClientController.java index e4966ad3..c76a1b22 100644 --- a/src/main/java/br/edu/utfpr/servicebook/controller/ClientController.java +++ b/src/main/java/br/edu/utfpr/servicebook/controller/ClientController.java @@ -32,10 +32,12 @@ import javax.persistence.EntityNotFoundException; import javax.servlet.http.HttpServletRequest; import java.io.IOException; +import java.text.SimpleDateFormat; import java.time.LocalDate; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; @RequestMapping("/minha-conta/cliente") @Controller @@ -104,6 +106,23 @@ public class ClientController { @Autowired private ProfessionalMapper professionalMapper; + @Autowired + private PaymentService paymentService; + + @Autowired + private PaymentMapper paymentMapper; + + @Autowired + private PaymentVoucherService paymentVoucherService; + + @Autowired + private PaymentVoucherMapper paymentVoucherMapper; + + @Autowired + private PaymentJobService paymentJobService; + + @Autowired + private PaymentJobMapper paymentJobMapper; /** * Método que apresenta a tela inicial do cliente @@ -776,4 +795,131 @@ public String markAsHided(@PathVariable Long jobId, @PathVariable Long userId, R return "redirect:/minha-conta/cliente/meus-pedidos/"+jobId; } + + /** + * Responsável por realizar o pagamento via API Mercado Pago. + */ + @PostMapping("/pagamento") + @RolesAllowed({RoleType.USER}) + public ResponseEntity createPayment(@RequestBody Map paymentData){ + ResponseDTO response = new ResponseDTO(); + + try { + if (paymentData == null || paymentData.isEmpty()) { + response.setMessage("Erro ao enviar dados. Verifique os campos e tente novamente!"); + return ResponseEntity.status(400).body(response); + } + + Optional oUser = (userService.findByEmail(authentication.getEmail())); + + if (!oUser.isPresent()) { + response.setMessage("Usuário não autenticado! Por favor, realize sua autenticação no sistema."); + return ResponseEntity.status(401).body(response); + } + + ResponseEntity paymentResponse = paymentService.pay(paymentData); + + if(!paymentResponse.getStatusCode().is2xxSuccessful()){ + response.setMessage("Erro ao processar pagamento. Tente novamente"); + return ResponseEntity.status(paymentResponse.getStatusCode()).body(response); + } + + Object responseBody = paymentResponse.getBody(); + + Map responseMap = (Map) responseBody; + Integer paymentId = (Integer) responseMap.get("id"); + String status = (String) responseMap.get("status"); + + PaymentDTO paymentDTO = new PaymentDTO(paymentId, status); + Payment payment = paymentMapper.toEntity(paymentDTO); + + paymentService.save(payment); + + response.setData(paymentResponse.getBody()); + return ResponseEntity.ok(response); + + } catch (Exception e) { + response.setMessage("Erro ao fazer pagamento. Por favor, tente novamente."); + return ResponseEntity.status(400).body(response); + } + } + + /** + * Apos processar o pagamento, ele é inserido na tabela payments_jobRequests + * contendo o id do pagamento e do serviço que foi realizado o pagamento. + * Finalizado este processo é preciso gerar um comprovante do pagamento + * tanto para cliente quanto profissional, que sera enviado por email + * **/ + @PostMapping("/pagamento/jobRequest") + @RolesAllowed({RoleType.USER}) + public ModelAndView savePaymentJob(@RequestBody PaymentJobDTO dto, BindingResult errors, RedirectAttributes redirectAttributes){ + ModelAndView modelAndView = new ModelAndView(); + final Date now = new Date(); + + Optional oPayment = paymentService.find(dto.getPaymentId()); + Optional oJobRequest = jobRequestService.findById(dto.getJobRequestId()); + + PaymentJobRequest paymentJob = new PaymentJobRequest(); + paymentJob.setJobRequestId(dto.getJobRequestId()); + paymentJob.setPayment(oPayment.get()); + paymentJob.setJobRequest(oJobRequest.get()); + paymentJob.setDateCreated(now); + + paymentJobService.save(paymentJob); + + createVoucherPayment(paymentJob); // GERA O COMPROVANTE DE PAGAMENTO + + modelAndView.addObject("mensagem", "Pagamento processado com sucesso!"); + + return modelAndView; + } + + public String createVoucherPayment(PaymentJobRequest paymentJob){ + /*Busca o job request - cliente*/ + Optional oJobRequest = jobRequestService.findById(paymentJob.getJobRequestId()); + + /*Traz o profissional*/ + Optional oJobContracted = jobContractedService.findByJobRequest(oJobRequest.get()); + + /*Traz o servico*/ + Optional oExpertise = expertiseService.findById(oJobRequest.get().getExpertise().getId()); + + PaymentVoucher paymentVoucher = new PaymentVoucher(); + paymentVoucher.setClient(oJobRequest.get().getUser()); + paymentVoucher.setProfessional(oJobContracted.get().getUser()); + paymentVoucher.setCode(gerarCodigoAlfanumerico()); + paymentVoucher.setJobRequest(oJobRequest.get()); + + String emailProfissional = oJobContracted.get().getUser().getEmail(); + String emailClient = oJobRequest.get().getUser().getEmail(); + + paymentVoucherService.save(paymentVoucher); + Date dataInicial = paymentJob.getDateCreated(); + Date dataAtual = new Date(); + + // Converter LocalDate para Date + SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); + + Calendar calendar = Calendar.getInstance(); + calendar.setTime(dataAtual); + + // Incrementando 15 dias + calendar.add(Calendar.DATE, 15); + + // Obtendo a nova data após o incremento + Date dataFinal = calendar.getTime(); + + /*Envio de email para o profissional*/ + quartzService.sendEmailPaymentVoucher(paymentVoucher.getCode(), + oJobRequest.get().getUser().getId(), oJobContracted.get().getUser().getId(), oExpertise.get().getName(), sdf.format(dataFinal)); + + return "redirect:/minha-conta/cliente#executados"; + } + + /* Gera código aleatorico e unico para gravação de comprovante */ + private String gerarCodigoAlfanumerico() { + UUID uuid = UUID.randomUUID(); + String codigo = uuid.toString().replace("-", "").substring(0, 10); + return codigo.toUpperCase(); + } } \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/jobs/SendEmailVoucher.java b/src/main/java/br/edu/utfpr/servicebook/jobs/SendEmailVoucher.java new file mode 100644 index 00000000..5c00ac80 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/jobs/SendEmailVoucher.java @@ -0,0 +1,72 @@ +package br.edu.utfpr.servicebook.jobs; + +import br.edu.utfpr.servicebook.service.EmailSenderService; +import br.edu.utfpr.servicebook.service.UserService; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import javax.mail.MessagingException; +import java.io.IOException; +import java.util.Optional; +import br.edu.utfpr.servicebook.model.entity.User; +import java.io.ByteArrayOutputStream; + + +@Component +public class SendEmailVoucher implements Job { + + public static final String PAYMENT_KEY = "token"; + public static final Long CLIENT_ID = Long.valueOf(0); + public static final Long PROFESSIONAL_ID = Long.valueOf(0); + public static final String SERVICE_KEY = "recipient_service"; + public static final String DATE_KEY = "recipient_date"; + + @Autowired + private EmailSenderService emailSenderService; + + @Autowired + private UserService userService; + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); + + String email1 = "thryssai@gmail.com"; + + String code = (String) jobDataMap.get(SendEmailVoucher.PAYMENT_KEY); + + Long clientId = (Long) jobDataMap.get(SendEmailVoucher.CLIENT_ID.toString()); + Optional oUser = userService.findById(clientId); + + Long professionalId = (Long) jobDataMap.get(SendEmailVoucher.PROFESSIONAL_ID.toString()); + Optional oProfessional = userService.findById(professionalId); + + String service = (String) jobDataMap.get(SendEmailVoucher.SERVICE_KEY); + + String date = (String) jobDataMap.get(SendEmailVoucher.DATE_KEY); + + String emailClient = (String) oUser.get().getEmail(); + String emailProfessional = (String) oProfessional.get().getEmail(); + + String text = "" + + "

        Olá, "+ email1 +"

        " + + "

        Segue o voucher por anexo que deverá ser apresentado no momento da realização do serviço.

        " + + "

        Qualquer informação pode ser obtida diretamente com o profissional, através do contato disponibilizado na plataforma.

        " + + "

        Atenciosamente,

        " + + "

        Equipe ServiceBook.

        " + + ""; + + String textProfessional = "" + + "

        Olá, "+ email1 +"

        " + + "

        Segue o voucher por anexo que deverá ser apresentado pelo cliente no momento da realização do serviço.

        " + + "

        Serviço solicitado por: "+ oUser.get().getName() +".

        " + + "

        Atenciosamente,

        " + + "

        Equipe ServiceBook.

        " + + ""; + + } + +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentDTO.java new file mode 100644 index 00000000..be5a0cdb --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentDTO.java @@ -0,0 +1,18 @@ +package br.edu.utfpr.servicebook.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PaymentDTO { + @NotEmpty(message = "O identificador do pagamento é obrigatório") + private Integer paymentId; + + @NotEmpty(message = "O status do pagamento é obrigatório") + private String status; +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentJobDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentJobDTO.java new file mode 100644 index 00000000..673cb931 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentJobDTO.java @@ -0,0 +1,14 @@ +package br.edu.utfpr.servicebook.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PaymentJobDTO { + private Long id; + private Long jobRequestId; + private Long paymentId; +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentVoucherDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentVoucherDTO.java new file mode 100644 index 00000000..43ce8d81 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/PaymentVoucherDTO.java @@ -0,0 +1,22 @@ +package br.edu.utfpr.servicebook.model.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.io.Serializable; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class PaymentVoucherDTO implements Serializable { + private Long id; + private Long paymentId; + private Long clientId; + private Long professionalId; + private Long jobRequestId; + + private String code; +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/Payment.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/Payment.java new file mode 100644 index 00000000..4f8eac0f --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/Payment.java @@ -0,0 +1,31 @@ +package br.edu.utfpr.servicebook.model.entity; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +import javax.persistence.*; +import java.util.List; + +@Data +@NoArgsConstructor +@RequiredArgsConstructor +@Table(name = "payments") +@Entity +public class Payment { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NonNull + @Column(unique = true) + private Integer paymentId; + + @NonNull + @Column() + private String status; + + @OneToMany(mappedBy = "payment", cascade = CascadeType.ALL) + private List paymentJobs; +} \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/PaymentJobRequest.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/PaymentJobRequest.java new file mode 100644 index 00000000..57fa8c8d --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/PaymentJobRequest.java @@ -0,0 +1,32 @@ +package br.edu.utfpr.servicebook.model.entity; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; + +import javax.persistence.*; +import java.util.Date; +import java.util.List; +@Data +@NoArgsConstructor +@Table(name = "payments_jobRequests") +@Entity +public class PaymentJobRequest { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NonNull + private Long jobRequestId; + + @ManyToOne + @JoinColumn(name = "payment_id", nullable = false) + private Payment payment; + + @ManyToOne + @JoinColumn(name = "jobrequest_id") + private JobRequest jobRequest; + + @Temporal(TemporalType.DATE) + private Date dateCreated; +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/PaymentVoucher.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/PaymentVoucher.java new file mode 100644 index 00000000..c01c7686 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/PaymentVoucher.java @@ -0,0 +1,32 @@ +package br.edu.utfpr.servicebook.model.entity; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.util.Date; + +@Data +@NoArgsConstructor +@Table(name = "payment_vouchers") +@Entity +public class PaymentVoucher { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String code; + + @ManyToOne + @JoinColumn(name = "client_id") + private User client; + + @ManyToOne + @JoinColumn(name = "professional_id") + private User professional; + + @ManyToOne + @JoinColumn(name = "jobrequest_id") + private JobRequest jobRequest; + +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentJobMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentJobMapper.java new file mode 100644 index 00000000..09621867 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentJobMapper.java @@ -0,0 +1,24 @@ +package br.edu.utfpr.servicebook.model.mapper; + +import br.edu.utfpr.servicebook.model.dto.PaymentJobDTO; +import br.edu.utfpr.servicebook.model.dto.PaymentVoucherDTO; +import br.edu.utfpr.servicebook.model.entity.PaymentJobRequest; +import br.edu.utfpr.servicebook.model.entity.PaymentVoucher; +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class PaymentJobMapper { + @Autowired + private ModelMapper mapper; + + public PaymentJobDTO toDTO(PaymentJobRequest entity) { + return mapper.map(entity, PaymentJobDTO.class); + } + + public PaymentJobRequest toEntity(PaymentJobDTO dto) { + PaymentJobRequest entity = mapper.map(dto, PaymentJobRequest.class); + return entity; + } +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentMapper.java new file mode 100644 index 00000000..a961716c --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentMapper.java @@ -0,0 +1,27 @@ +package br.edu.utfpr.servicebook.model.mapper; + + +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import br.edu.utfpr.servicebook.model.dto.PaymentDTO; +import br.edu.utfpr.servicebook.model.entity.Payment; + +@Component +public class PaymentMapper { + + @Autowired + private ModelMapper mapper; + + public PaymentDTO toDto(Payment entity) { + PaymentDTO dto = mapper.map(entity, PaymentDTO.class); + return dto; + } + + public Payment toEntity(PaymentDTO dto) { + Payment entity = mapper.map(dto, Payment.class); + return entity; + } + +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentVoucherMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentVoucherMapper.java new file mode 100644 index 00000000..886ec30d --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/PaymentVoucherMapper.java @@ -0,0 +1,24 @@ +package br.edu.utfpr.servicebook.model.mapper; + +import br.edu.utfpr.servicebook.model.dto.PaymentVoucherDTO; +import br.edu.utfpr.servicebook.model.dto.ProfessionalExpertiseDTO; +import br.edu.utfpr.servicebook.model.entity.PaymentVoucher; +import br.edu.utfpr.servicebook.model.entity.ProfessionalExpertise; +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class PaymentVoucherMapper { + @Autowired + private ModelMapper mapper; + + public PaymentVoucherDTO toDTO(PaymentVoucher entity) { + return mapper.map(entity, PaymentVoucherDTO.class); + } + + public PaymentVoucher toEntity(PaymentVoucherDTO dto) { + PaymentVoucher entity = mapper.map(dto, PaymentVoucher.class); + return entity; + } +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentJobRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentJobRepository.java new file mode 100644 index 00000000..4125693f --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentJobRepository.java @@ -0,0 +1,22 @@ +package br.edu.utfpr.servicebook.model.repository; + +import br.edu.utfpr.servicebook.model.entity.JobRequest; +import br.edu.utfpr.servicebook.model.entity.PaymentJobRequest; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface PaymentJobRepository extends JpaRepository { + List findAll(); + + Page findAll(Pageable pageable); + + List findAllById(Iterable longs); + + Optional findByJobRequest(JobRequest id); +} diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentRepository.java new file mode 100644 index 00000000..eff63f00 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentRepository.java @@ -0,0 +1,13 @@ +package br.edu.utfpr.servicebook.model.repository; + +import br.edu.utfpr.servicebook.model.entity.Payment; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PaymentRepository extends JpaRepository{ + + +} + diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentVoucherRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentVoucherRepository.java new file mode 100644 index 00000000..db2bf473 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/PaymentVoucherRepository.java @@ -0,0 +1,22 @@ +package br.edu.utfpr.servicebook.model.repository; + +import br.edu.utfpr.servicebook.model.entity.PaymentVoucher; +import br.edu.utfpr.servicebook.model.entity.Service; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface PaymentVoucherRepository extends JpaRepository { + + List findAll(); + + + Page findAll(Pageable pageable); + + List findAllById(Iterable longs); +} diff --git a/src/main/java/br/edu/utfpr/servicebook/service/PaymentJobService.java b/src/main/java/br/edu/utfpr/servicebook/service/PaymentJobService.java new file mode 100644 index 00000000..0c07761e --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/service/PaymentJobService.java @@ -0,0 +1,32 @@ +package br.edu.utfpr.servicebook.service; + +import br.edu.utfpr.servicebook.model.entity.JobRequest; +import br.edu.utfpr.servicebook.model.entity.PaymentJobRequest; +import br.edu.utfpr.servicebook.model.repository.PaymentJobRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class PaymentJobService { + @Autowired + private PaymentJobRepository paymentJobRepository; + + public void save(PaymentJobRequest entity) { + paymentJobRepository.save(entity); + } + + public List findAll() { + return this.paymentJobRepository.findAll(); + } + + public Optional findById(Long id) { + return this.paymentJobRepository.findById(id); + } + + public Optional findByJobRequest(JobRequest id) { + return this.paymentJobRepository.findByJobRequest(id); + } +} diff --git a/src/main/java/br/edu/utfpr/servicebook/service/PaymentService.java b/src/main/java/br/edu/utfpr/servicebook/service/PaymentService.java new file mode 100644 index 00000000..47d109ae --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/service/PaymentService.java @@ -0,0 +1,53 @@ +package br.edu.utfpr.servicebook.service; +import java.util.Map; +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import br.edu.utfpr.servicebook.model.entity.Payment; +import br.edu.utfpr.servicebook.model.repository.PaymentRepository; + + +@Service +public class PaymentService { + + private final Environment environment; + + @Autowired + private PaymentRepository paymentRepository; + + @Autowired + public PaymentService(Environment environment){ + this.environment = environment; + } + + public ResponseEntity pay(Map paymentData){ + RestTemplate restTemplate = new RestTemplate(); + String apiUrl = "https://api.mercadopago.com/v1/payments"; + + try { + String accessToken = environment.getProperty("MP_ACCESS_TOKEN"); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setBearerAuth(accessToken); + + HttpEntity> requestEntity = new HttpEntity<>(paymentData, headers); + + ResponseEntity response = restTemplate.exchange(apiUrl, HttpMethod.POST, requestEntity, Object.class); + return response; + + } catch (Exception e) { + throw new RuntimeException("Algo deu errado! Tente novamente."); + } + + } + + public Payment save(Payment entity){ return paymentRepository.save(entity); } + + public Optional find(Long payment){ return paymentRepository.findById(payment); } +} diff --git a/src/main/java/br/edu/utfpr/servicebook/service/PaymentVoucherService.java b/src/main/java/br/edu/utfpr/servicebook/service/PaymentVoucherService.java new file mode 100644 index 00000000..7dde4d22 --- /dev/null +++ b/src/main/java/br/edu/utfpr/servicebook/service/PaymentVoucherService.java @@ -0,0 +1,29 @@ +package br.edu.utfpr.servicebook.service; + +import br.edu.utfpr.servicebook.model.entity.PaymentVoucher; +import br.edu.utfpr.servicebook.model.repository.PaymentVoucherRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +public class PaymentVoucherService { + + @Autowired + private PaymentVoucherRepository paymentVoucherRepository; + + public void save(PaymentVoucher entity) { + paymentVoucherRepository.save(entity); + } + + public List findAll() { + return this.paymentVoucherRepository.findAll(); + } + + public Optional findById(Long id) { + return this.paymentVoucherRepository.findById(id); + } + +} diff --git a/src/main/java/br/edu/utfpr/servicebook/service/QuartzService.java b/src/main/java/br/edu/utfpr/servicebook/service/QuartzService.java index de9d2e74..af77302a 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/QuartzService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/QuartzService.java @@ -213,4 +213,30 @@ public void deleteJobsAvailableToHide() { System.out.println(e.getMessage()); } } + + /** Envio de email para o cliente e profissional com o comprovante de pagamento*/ + public void sendEmailPaymentVoucher(String codePayment, Long client, Long professional, String service, String date) { + try { + System.out.println("clientId---------------------"); + System.out.println(client); + JobDetail job = JobBuilder.newJob(SendEmailVoucher.class) + .withIdentity(SendEmailVoucher.class.getSimpleName(), GROUP).build(); + job.getJobDataMap().put(SendEmailVoucher.PAYMENT_KEY, codePayment); + job.getJobDataMap().put(String.valueOf((Long) SendEmailVoucher.CLIENT_ID), client); + job.getJobDataMap().put(String.valueOf(SendEmailVoucher.PROFESSIONAL_ID), professional); + job.getJobDataMap().put(SendEmailVoucher.SERVICE_KEY, service); + job.getJobDataMap().put(SendEmailVoucher.DATE_KEY, date); + + Trigger trigger = getTrigger(SendEmailWithVerificationCodeJob.class.getSimpleName(), GROUP); + + scheduler.scheduleJob(job, trigger); + + if (!scheduler.isStarted()) { + scheduler.start(); + } + + }catch (SchedulerException e){ + System.out.println(e.getMessage()); + } + } } diff --git a/src/main/webapp/WEB-INF/view/client/details-request.jsp b/src/main/webapp/WEB-INF/view/client/details-request.jsp index e1455787..9eddd236 100644 --- a/src/main/webapp/WEB-INF/view/client/details-request.jsp +++ b/src/main/webapp/WEB-INF/view/client/details-request.jsp @@ -7,6 +7,15 @@ + + + @@ -108,6 +117,25 @@ >
        + + + +
        +
        + + +
        +
        diff --git a/src/main/webapp/assets/resources/scripts/mp-payment.js b/src/main/webapp/assets/resources/scripts/mp-payment.js new file mode 100644 index 00000000..373d1371 --- /dev/null +++ b/src/main/webapp/assets/resources/scripts/mp-payment.js @@ -0,0 +1,145 @@ + +function showPayment(jobRequestId) { + + if ($(".brick-payment").is(":hidden")) { + $('.brick-payment').fadeIn(); + $('.brick-status').fadeIn(); + + } + else{ + $('.brick-payment').fadeOut(); + $('.brick-status').fadeOut(); + return; + } + + const renderPaymentBrick = async (bricksBuilder) => { + const settings = { + initialization: { + amount: 0.5, + }, + customization: { + paymentMethods: { + ticket: "all", + bankTransfer: "all", + creditCard: "all", + debitCard: "all", + mercadoPago: "all", + }, + }, + callbacks: { + onReady: () => {}, + onSubmit: ({ + selectedPaymentMethod, + formData + }) => { + console.log(jobRequestId) + // callback chamado ao clicar no botão de submissão dos dados + return new Promise((resolve, reject) => { + fetch("minha-conta/cliente/pagamento", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(formData), + }) + .then(response => { + if (!response.ok) { + return response.json().then(responseBody => { + throw new Error(responseBody.message); + }); + } + + return response.json(); + }) + .then((response) => { + const paymentId = response.data.id; + renderStatusScreenBrick(bricksBuilder, paymentId); + // sendPaymentVoucher(paymentId); + paymentJobRequest(paymentId, jobRequestId); + resolve(); + }) + .catch((error) => { + swal({ + title: "Opss", + text: error.message, + icon: "error", + }); + reject(); + }); + }); + }, + onError: (error) => { + console.error(error); + }, + }, + }; + + bricksBuilder.create( + "payment", + "paymentBrick_container", + settings + ) + .then(paymentBrickController => { + + }) + .catch(error => { + console.error(error); + }); + }; + + renderPaymentBrick(bricksBuilder); +} + + +const renderStatusScreenBrick = async (bricksBuilder, paymentId) => { + const settings = { + initialization: { + paymentId: paymentId, + }, + callbacks: { + onReady: () => { + /* + Callback chamado quando o Brick estiver pronto. + Aqui você pode ocultar loadings do seu site, por exemplo. + */ + }, + onError: (error) => { + console.error(error); + }, + }, + }; + + window.statusScreenBrickController = await bricksBuilder.create( + 'statusScreen', + 'statusScreenBrick_container', + settings, + ); +}; + +function paymentJobRequest(paymentId, jobRequestId) { + const URL = "/servicebook/minha-conta/cliente/pagamento/jobRequest"; + + var dto = { + id: null, + jobRequestId: jobRequestId, + paymentId: 1, + }; + + fetch(URL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(dto), + }).then((response) => { + console.log(response) + if (response.ok) { + return response.json(); + } + }).then((data) => { + console.log('ID do item salvo:', data); + }).catch((error) => { + console.error('Erro ao processar a solicitação:', error); + alert("Houve um problema, não foi possível seguir."); + }); +} From 4d5e1f190f9fb9c65f32d2a5ed09a831ea340dbe Mon Sep 17 00:00:00 2001 From: TaisHryssai Date: Sun, 26 May 2024 18:48:04 -0300 Subject: [PATCH 9/9] layout adjustments --- .../controller/ClientController.java | 107 ++++++ .../controller/JobRequestController.java | 11 +- .../controller/ProfessionalController.java | 75 ++++- .../model/dto/JobContractedFullDTO.java | 3 + .../model/dto/JobRequestDetailsDTO.java | 2 + .../model/dto/JobRequestFullDTO.java | 9 + .../model/dto/ProfessionalSearchItemDTO.java | 5 +- .../servicebook/model/entity/JobRequest.java | 3 +- .../entity/ProfessionalServiceOffering.java | 2 +- .../model/mapper/IndividualMapper.java | 1 + .../model/mapper/JobContractedMapper.java | 8 +- .../model/mapper/JobRequestMapper.java | 8 +- .../repository/IndividualRepository.java | 20 ++ .../service/IndividualService.java | 13 + .../service/JobRequestService.java | 8 + .../servicebook/service/PaymentService.java | 2 +- src/main/webapp/WEB-INF/tags/banner.tag | 2 +- .../webapp/WEB-INF/tags/navbar-client.tag | 3 - .../WEB-INF/tags/professional-order-card.tag | 142 ++++---- src/main/webapp/WEB-INF/tags/search-bar.tag | 146 ++++---- .../tags/side-panel-dashboard-admin.tag | 2 +- src/main/webapp/WEB-INF/tags/side-panel.tag | 21 +- src/main/webapp/WEB-INF/tags/template.tag | 8 +- .../view/client/details-request-candidate.jsp | 128 +++++-- .../WEB-INF/view/client/details-request.jsp | 68 ++-- .../tabs/available-jobs-report.jsp | 140 ++++---- .../job-request/tabs/doing-jobs-report.jsp | 66 ++-- .../job-request/tabs/executed-jobs-report.jsp | 114 +++++-- .../view/professional/account/my-ad.jsp | 11 +- .../professional/account/my-contact-phone.jsp | 5 + .../view/professional/account/my-email.jsp | 5 + .../view/professional/account/my-password.jsp | 5 + .../professional/account/my-personal-info.jsp | 6 + .../view/professional/budget-jobs-report.jsp | 128 ++++--- .../professional/disputed-jobs-report.jsp | 126 ++++--- .../professional/jobs-performed-report.jsp | 105 +++--- .../view/professional/my-account-menu.jsp | 16 +- .../view/professional/my-ads-register.jsp | 49 ++- .../WEB-INF/view/professional/my-ads.jsp | 4 +- .../view/professional/my-expertises.jsp | 6 + .../WEB-INF/view/professional/my-services.jsp | 6 + .../view/professional/professional-index.jsp | 315 +++++++++++++----- .../professional/to-hired-jobs-report.jsp | 130 ++++---- .../view/professional/todo-jobs-report.jsp | 95 +++--- .../webapp/WEB-INF/view/visitor/index.jsp | 62 ++-- .../view/visitor/professional-details.jsp | 71 ++-- .../WEB-INF/view/visitor/search-results.jsp | 186 +++++++---- .../assets/resources/scripts/banner-hidden.js | 20 ++ .../webapp/assets/resources/scripts/main.js | 119 ------- .../assets/resources/scripts/mp-payment.js | 59 ++-- .../webapp/assets/resources/scripts/search.js | 29 +- .../assets/resources/styles/admin/admin.css | 1 + .../assets/resources/styles/banner-hidden.css | 34 ++ .../assets/resources/styles/client/client.css | 106 ++++++ .../webapp/assets/resources/styles/colors.css | 4 + .../resources/styles/professional/ads.css | 2 +- .../styles/professional/professional.css | 134 ++++++++ .../webapp/assets/resources/styles/styles.css | 31 +- .../resources/styles/visitor/visitor.css | 41 ++- 59 files changed, 2024 insertions(+), 1004 deletions(-) create mode 100644 src/main/webapp/assets/resources/scripts/banner-hidden.js create mode 100644 src/main/webapp/assets/resources/styles/banner-hidden.css diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/ClientController.java b/src/main/java/br/edu/utfpr/servicebook/controller/ClientController.java index ded53a38..cf7e2542 100644 --- a/src/main/java/br/edu/utfpr/servicebook/controller/ClientController.java +++ b/src/main/java/br/edu/utfpr/servicebook/controller/ClientController.java @@ -18,6 +18,11 @@ import br.edu.utfpr.servicebook.util.TemplateUtil; import com.cloudinary.Cloudinary; import com.cloudinary.utils.ObjectUtils; +import com.mercadopago.client.common.AddressRequest; +import com.mercadopago.client.common.IdentificationRequest; +import com.mercadopago.client.common.PhoneRequest; +import com.mercadopago.client.preference.*; +import com.mercadopago.resources.preference.Preference; import org.apache.batik.transcoder.TranscoderException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,6 +43,7 @@ import javax.xml.transform.TransformerException; import java.io.File; import java.io.IOException; +import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.util.*; @@ -47,6 +53,7 @@ import com.google.zxing.WriterException; import org.apache.batik.transcoder.TranscoderException; import org.apache.fop.configuration.ConfigurationException; +import com.mercadopago.MercadoPagoConfig; @RequestMapping("/minha-conta/cliente") @Controller @@ -258,6 +265,106 @@ public ModelAndView showDetailsRequest(@PathVariable Optional id) throws E }) .collect(Collectors.toList()); + MercadoPagoConfig.setAccessToken("TEST-2738533774159236-052518-f4e09de99516f8d7b2adb21186313d1b-494777183"); + PreferenceClient client = new PreferenceClient(); + + PreferenceItemRequest itemRequest = + PreferenceItemRequest.builder() + .id("1234") + .title("Dummy Title") + .description("Dummy description") + .pictureUrl("http://www.myapp.com/myimage.jpg") + .categoryId("car_electronics") + .quantity(1) + .currencyId("BRL") + .unitPrice(new BigDecimal("10")) + .build(); + + List items = new ArrayList<>(); + items.add(itemRequest); + + PreferenceFreeMethodRequest freeMethod = + PreferenceFreeMethodRequest.builder() + .id(1L).build(); + List freeMethodList = new ArrayList<>(); + freeMethodList.add(freeMethod); + + List excludedPaymentTypes = new ArrayList<>(); + excludedPaymentTypes.add(PreferencePaymentTypeRequest.builder().id("ticket").build()); + + List excludedPaymentMethods = new ArrayList<>(); + excludedPaymentMethods.add(PreferencePaymentMethodRequest.builder().id("").build()); + + PreferenceRequest preferenceRequest = PreferenceRequest.builder() + .backUrls( + PreferenceBackUrlsRequest.builder() + .success("http://test.com/success") + .failure("http://test.com/failure") + .pending("http://test.com/pending") + .build()) + .differentialPricing( + PreferenceDifferentialPricingRequest.builder() + .id(1L) + .build()) + .expires(false) + .items(items) + .marketplaceFee(new BigDecimal("0")) + .payer( + PreferencePayerRequest.builder() + .name("Test") + .surname("User") + .email("your_test_email@example.com") + .phone(PhoneRequest.builder().areaCode("11").number("4444-4444").build()) + .identification( + IdentificationRequest.builder().type("CPF").number("19119119100").build()) + .address( + AddressRequest.builder() + .zipCode("06233200") + .streetName("Street") + .streetNumber("123") + .build()) + .build()) + .additionalInfo("Discount: 12.00") + .autoReturn("all") + .binaryMode(true) + .externalReference("1643827245") + .marketplace("marketplace") + .notificationUrl("http://notificationurl.com") + .operationType("regular_payment") + .paymentMethods( + PreferencePaymentMethodsRequest.builder() + .defaultPaymentMethodId("master") + .excludedPaymentTypes(excludedPaymentTypes) + .excludedPaymentMethods(excludedPaymentMethods) + .installments(5) + .defaultInstallments(1) + .build()) + .shipments( + PreferenceShipmentsRequest.builder() + .mode("custom") + .localPickup(false) + .defaultShippingMethod(null) + .freeMethods(freeMethodList) + .cost(BigDecimal.TEN) + .freeShipping(false) + .dimensions("10x10x20,500") + .receiverAddress( + PreferenceReceiverAddressRequest.builder() + .zipCode("06000000") + .streetNumber("123") + .streetName("Street") + .floor("12") + .apartment("120A") + .build()) + .build()) + .statementDescriptor("Test Store") + .build(); + + Preference preference = client.create(preferenceRequest); + + + System.out.println("AAAAAAA"); + System.out.println(preference.getClientId()); mv.addObject("candidates", jobCandidatesDTOs); mv.addObject("expertise", expertiseDTO); mv.addObject("jobRequest", jobDTO); diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/JobRequestController.java b/src/main/java/br/edu/utfpr/servicebook/controller/JobRequestController.java index 3f7fd2e2..43bec1a8 100644 --- a/src/main/java/br/edu/utfpr/servicebook/controller/JobRequestController.java +++ b/src/main/java/br/edu/utfpr/servicebook/controller/JobRequestController.java @@ -116,6 +116,7 @@ public int getValue(){ @GetMapping @PermitAll public String showWizard(@RequestParam(value = "passo", required = false, defaultValue = "1") Long step, + @RequestParam(value = "especialidade", required = false, defaultValue = "0") Long expertiseId, HttpSession httpSession, Model model) throws Exception { log.debug("Mostrando o passo {}", step); @@ -133,6 +134,11 @@ public String showWizard(@RequestParam(value = "passo", required = false, defaul JobRequestDTO dto = wizardSessionUtil.getWizardState(httpSession, JobRequestDTO.class, WizardSessionUtil.KEY_WIZARD_JOB_REQUEST); model.addAttribute("dto", dto); + if(expertiseId != 0){ + JobRequestDTO sessionDTO = wizardSessionUtil.getWizardState(httpSession, JobRequestDTO.class, WizardSessionUtil.KEY_WIZARD_JOB_REQUEST); + sessionDTO.setExpertiseId(expertiseId); + } + if(step == 1L){ List expertise = expertiseService.findAll(); List expertiseDTOs = expertise.stream() @@ -182,7 +188,6 @@ public String saveFormRequestedJob(HttpSession httpSession, @Validated(JobReques @PermitAll public String saveFormDateJob(HttpSession httpSession, @Validated(JobRequestDTO.RequestExpirationGroupValidation.class) JobRequestDTO dto, BindingResult errors, RedirectAttributes redirectAttributes, Model model) throws Exception { - if(errors.hasErrors()){ model.addAttribute("dto", dto); model.addAttribute("errors", errors.getAllErrors()); @@ -225,7 +230,7 @@ public String saveFormDateJob(HttpSession httpSession, @Validated(JobRequestDTO. } sessionDTO.setDateTarget(DateUtil.getToday()); log.debug("Passo 2 {}", sessionDTO); - return "redirect:/requisicoes?passo=3"; + return "redirect:/requisicoes?passo=4"; } @PostMapping("/passo-3") @@ -300,7 +305,7 @@ public String saveFormImagePath(HttpSession httpSession, RedirectAttributes redi sessionDTO.setImageSession((String)data.get("url")); log.debug("Passo 5 {}", sessionDTO); - return "redirect:/requisicoes?passo=8"; + return "redirect:/requisicoes?passo=7"; } else { return "redirect:/requisicoes/passo=5"; } diff --git a/src/main/java/br/edu/utfpr/servicebook/controller/ProfessionalController.java b/src/main/java/br/edu/utfpr/servicebook/controller/ProfessionalController.java index 72c48a9f..bac1a068 100644 --- a/src/main/java/br/edu/utfpr/servicebook/controller/ProfessionalController.java +++ b/src/main/java/br/edu/utfpr/servicebook/controller/ProfessionalController.java @@ -172,15 +172,23 @@ protected ModelAndView showSearchResults( .map(s -> categoryMapper.toDto(s)) .collect(Collectors.toList()); - PaginationDTO paginationDTO = paginationUtil.getPaginationDTO(professionals, "/profissionais/busca?termo-da-busca=" + searchService); + Page professionalsByExpertise = individualService.findDistinctByExpertiseAndCategoryPagination(expertise.get(), page, size); + Page listProfessionals = individualService.listByExpertiseAndCategory(expertise.get(), category.get(), page, size); + + List professionalSearchItemDTOS2 = professionalsByExpertise.stream() + .map(s -> individualMapper.toSearchItemDto(s, individualService.getExpertises(s))) + .collect(Collectors.toList()); List professionals1 = individualService.findAllIndividualsAutonomosByService(expertise.get().getId(), page, size); + List professionalSearchItemDTOS1 = professionals1.stream() .map(s -> individualMapper.toSearchItemDto(s, individualService.getExpertises(s))) .collect(Collectors.toList()); - mv.addObject("professionals", professionals1); + PaginationDTO paginationDTO = paginationUtil.getPaginationDTO(professionalServiceOfferings, "/profissionais/busca?termo-da-busca=" + searchService); + + mv.addObject("professionals", professionalSearchItemDTOS2); mv.addObject("categoryDTOs", categoryDTOs); mv.addObject("pagination", paginationDTO); mv.addObject("isParam", true); @@ -191,6 +199,7 @@ protected ModelAndView showSearchResults( mv.addObject("dto_service", service.get()); mv.addObject("professionalServiceOfferingDTOS", professionalServiceOfferingDTOS); + mv.addObject("count_results", professionalServiceOfferingDTOS.size()); } return mv; @@ -258,4 +267,66 @@ protected ModelAndView showProfessionalDetailsToVisitors(@PathVariable("id") Lon } return mv; } + + @GetMapping("/detalhes/{id}/servico/{service_id}") + @PermitAll + protected ModelAndView showProfessionalDetailsAndServiceToVisitors(@PathVariable("id") Long id, @PathVariable("service_id") Long service_id) throws Exception { + + Optional oProfessional = userService.findById(id); + + if (!oProfessional.isPresent()) { + throw new EntityNotFoundException("Profissional não encontrado."); + } + + Optional oService = serviceService.findById(service_id); + + if (!oService.isPresent()) { + throw new EntityNotFoundException("Serviço não encontrado."); + } + + //cliente autenticado, caso esteja logado + Optional oClientAuthenticated = (userService.findByEmail(authentication.getEmail())); + + //profissional requisitado + UserDTO professionalDTO = userMapper.toDto(oProfessional.get()); + + //especialidades do profissional requisitado + List expertisesDTO = userService.getExpertiseDTOs(oProfessional.get()); + + List professionalExpertises = professionalExpertiseService.findByProfessional(oProfessional.get()); + + //serviços por especialidade + Map> servicesByExpertise = new HashMap<>(); + for (ProfessionalExpertise pe : professionalExpertises) { + List professionalServiceOfferings = professionalServiceOfferingService.findProfessionalServiceOfferingByUserAndExpertise(oProfessional.get().getId(), pe.getExpertise().getId()); + + if (professionalServiceOfferings.isEmpty()) { + continue; + } + + //transforma para DTO + List professionalServiceOfferingsDTO = professionalServiceOfferings.stream() + .map(service -> professionalServiceOfferingMapper.toDTO(service)) + .collect(Collectors.toList()); + + servicesByExpertise.put(pe, professionalServiceOfferingsDTO); + } + + ModelAndView mv = new ModelAndView("visitor/professional-details"); + mv.addObject("professional", professionalDTO); + mv.addObject("professionalExpertises", expertisesDTO); + mv.addObject("logged", oClientAuthenticated.isPresent()); + mv.addObject("servicesByExpertise", servicesByExpertise); + mv.addObject("service", oService.get()); + + //se o cliente está logado, mostra se ele segue o profissional + if (oClientAuthenticated.isPresent()) { + List follows = followsService.findFollowProfessionalClient(oProfessional.get(), oClientAuthenticated.get()); + boolean isFollow = !follows.isEmpty(); + UserDTO clientDTO = userMapper.toDto(oClientAuthenticated.get()); + mv.addObject("isFollow", isFollow); + mv.addObject("client", clientDTO); + } + return mv; + } } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/JobContractedFullDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/JobContractedFullDTO.java index 7293c57f..4c3151ba 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/dto/JobContractedFullDTO.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/JobContractedFullDTO.java @@ -4,6 +4,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.time.LocalDate; + @Data @NoArgsConstructor @AllArgsConstructor @@ -13,5 +15,6 @@ public class JobContractedFullDTO { private String comments; private int rating; private JobRequestFullDTO jobRequest; + private String todoDate; } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestDetailsDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestDetailsDTO.java index 08de75f4..29c22e13 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestDetailsDTO.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestDetailsDTO.java @@ -3,6 +3,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import org.springframework.web.multipart.MultipartFile; import java.io.Serializable; @@ -21,5 +22,6 @@ public class JobRequestDetailsDTO implements Serializable { private Long totalCandidates; private String textualDate; private Long amountOfCandidates; + private MultipartFile imageFile; } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestFullDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestFullDTO.java index 9d5bae45..ba3495de 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestFullDTO.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/JobRequestFullDTO.java @@ -1,10 +1,15 @@ package br.edu.utfpr.servicebook.model.dto; +import br.edu.utfpr.servicebook.model.entity.JobImages; +import br.edu.utfpr.servicebook.model.entity.User; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import org.springframework.web.multipart.MultipartFile; import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; @Data @NoArgsConstructor @@ -21,7 +26,11 @@ public class JobRequestFullDTO implements Serializable { private Long totalCandidates; private String textualDate; private Long amountOfCandidates; + private User user; public String status; + private MultipartFile imageFile; + private Set jobImages = new HashSet<>(); + } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalSearchItemDTO.java b/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalSearchItemDTO.java index 48eada24..27c502e7 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalSearchItemDTO.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/dto/ProfessionalSearchItemDTO.java @@ -1,5 +1,7 @@ package br.edu.utfpr.servicebook.model.dto; +import br.edu.utfpr.servicebook.model.entity.Expertise; +import br.edu.utfpr.servicebook.model.entity.Individual; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -20,10 +22,11 @@ public class ProfessionalSearchItemDTO extends UserDTO { private int rating; private int denounceAmount; - public String getOnlyNumbersFromPhone() { return getPhoneNumber().replaceAll("[^0-9]", ""); } public List expertises; + + public Expertise expertise; } \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/JobRequest.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/JobRequest.java index 11a73c12..356fe810 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/entity/JobRequest.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/JobRequest.java @@ -6,6 +6,7 @@ import javax.persistence.*; +import br.edu.utfpr.servicebook.model.dto.ClientMinDTO; import lombok.*; @Data @@ -39,7 +40,7 @@ public enum Status { @ManyToOne @JoinColumn(name = "client_id") private User user; - + @ManyToOne @JoinColumn(name = "expertise_id") private Expertise expertise; diff --git a/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOffering.java b/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOffering.java index 0291489b..2757a111 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOffering.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/entity/ProfessionalServiceOffering.java @@ -13,7 +13,7 @@ * Ele pode ter várias customizações para um mesmo serviço cadastrado pelo Administrador. */ @Data -@Table(name = "professional_service_offerings") + @Table(name = "professional_service_offerings") @NoArgsConstructor @Entity public class ProfessionalServiceOffering { diff --git a/src/main/java/br/edu/utfpr/servicebook/model/mapper/IndividualMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/IndividualMapper.java index 36cda32e..298cda4b 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/mapper/IndividualMapper.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/IndividualMapper.java @@ -2,6 +2,7 @@ import br.edu.utfpr.servicebook.model.dto.*; +import br.edu.utfpr.servicebook.model.entity.Expertise; import br.edu.utfpr.servicebook.model.entity.Individual; import br.edu.utfpr.servicebook.util.UserTemplateInfo; import org.modelmapper.ModelMapper; diff --git a/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobContractedMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobContractedMapper.java index e3e6d201..12c55d64 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobContractedMapper.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobContractedMapper.java @@ -8,12 +8,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.time.format.DateTimeFormatter; import java.util.Optional; @Component public class JobContractedMapper { @Autowired private ModelMapper mapper; + private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); public JobContractedDTO toDto(JobContracted entity) { JobContractedDTO dto = mapper.map(entity, JobContractedDTO.class); @@ -40,7 +42,11 @@ public JobContractedFullDTO toFullDto(JobContracted entity, Optional total JobContractedFullDTO dto = mapper.map(entity, JobContractedFullDTO.class); dto.getJobRequest().setTotalCandidates(totalCandidates.get()); dto.getJobRequest().setTextualDate(DateUtil.getTextualDate((entity.getJobRequest().getDateTarget()))); - + dto.getJobRequest().setIndividual(dto.getJobRequest().getIndividual()); + if(entity.getJobRequest().getDateCreated() != null) { + dto.getJobRequest().setDateCreated(this.dateTimeFormatter.format(entity.getJobRequest().getDateCreated())); + } + dto.setTodoDate(this.dateTimeFormatter.format(entity.getTodoDate())); return dto; } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobRequestMapper.java b/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobRequestMapper.java index e2ee128d..d9747ac3 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobRequestMapper.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/mapper/JobRequestMapper.java @@ -1,10 +1,7 @@ package br.edu.utfpr.servicebook.model.mapper; -import br.edu.utfpr.servicebook.model.dto.JobRequestDTO; -import br.edu.utfpr.servicebook.model.dto.JobRequestDetailsDTO; -import br.edu.utfpr.servicebook.model.dto.JobRequestFullDTO; -import br.edu.utfpr.servicebook.model.dto.JobRequestMinDTO; +import br.edu.utfpr.servicebook.model.dto.*; import br.edu.utfpr.servicebook.model.entity.JobRequest; import br.edu.utfpr.servicebook.util.DateUtil; import org.modelmapper.ModelMapper; @@ -71,6 +68,9 @@ public JobRequestFullDTO toFullDto(JobRequest entity, Optional totalCandid dto.setDateTarget(this.dateTimeFormatter.format(entity.getDateTarget())); dto.setTextualDate(DateUtil.getTextualDate((entity.getDateTarget()))); + dto.setUser(entity.getUser()); + dto.setJobImages(entity.getJobImages()); + return dto; } diff --git a/src/main/java/br/edu/utfpr/servicebook/model/repository/IndividualRepository.java b/src/main/java/br/edu/utfpr/servicebook/model/repository/IndividualRepository.java index 3599f030..409c7c50 100644 --- a/src/main/java/br/edu/utfpr/servicebook/model/repository/IndividualRepository.java +++ b/src/main/java/br/edu/utfpr/servicebook/model/repository/IndividualRepository.java @@ -1,5 +1,9 @@ package br.edu.utfpr.servicebook.model.repository; +import br.edu.utfpr.servicebook.model.dto.IndividualDTO; +import br.edu.utfpr.servicebook.model.dto.ProfessionalSearchItemDTO; +import br.edu.utfpr.servicebook.model.entity.Category; +import br.edu.utfpr.servicebook.model.entity.Expertise; import br.edu.utfpr.servicebook.model.entity.Individual; import br.edu.utfpr.servicebook.model.entity.Service; import org.springframework.data.domain.Page; @@ -66,4 +70,20 @@ Page findAllIndividualsByService( List findAllIndividualsAutonomosByService( Long term, Pageable pageable); + + @Query("select distinct p from Individual p left join ProfessionalExpertise pe on p.id = pe.professional.id " + + " left join Expertise ex on pe.expertise.id = ex.id "+ + "where pe.expertise = :expertiseId ") + Page findDistinctByExpertiseAndCategoryPagination( + Expertise expertiseId, + Pageable pageable); + + @Query("select distinct ex from Individual p left join ProfessionalExpertise pe on p.id = pe.professional.id " + + " left join Expertise ex on pe.expertise.id = ex.id "+ + "where pe.expertise = :expertiseId or pe.expertise.category = :categoryId") + Page listByExpertiseAndCategory( + Expertise expertiseId, + Category categoryId, + Pageable pageable); + } \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/service/IndividualService.java b/src/main/java/br/edu/utfpr/servicebook/service/IndividualService.java index 9d9f93a2..a201c701 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/IndividualService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/IndividualService.java @@ -1,6 +1,8 @@ package br.edu.utfpr.servicebook.service; import br.edu.utfpr.servicebook.model.dto.ExpertiseDTO; +import br.edu.utfpr.servicebook.model.dto.IndividualDTO; +import br.edu.utfpr.servicebook.model.dto.ProfessionalSearchItemDTO; import br.edu.utfpr.servicebook.model.entity.*; import br.edu.utfpr.servicebook.model.mapper.ExpertiseMapper; import br.edu.utfpr.servicebook.model.repository.CompanyRepository; @@ -144,4 +146,15 @@ public void saveExpertisesCompany(Company company, ProfessionalExpertise profess professionalExpertiseRepository.save(professionalExpertise); companyRepository.save(company); } + + public Page findDistinctByExpertiseAndCategoryPagination(Expertise expertiseId, Integer page, Integer size){ + PageRequest pageRequest = PageRequest.of(page - 1, size); + return this.individualRepository.findDistinctByExpertiseAndCategoryPagination(expertiseId, pageRequest); + } + + public Page listByExpertiseAndCategory(Expertise expertiseId, Category categoryId, Integer page, Integer size){ + PageRequest pageRequest = PageRequest.of(page - 1, size); + return this.individualRepository.listByExpertiseAndCategory(expertiseId, categoryId, pageRequest); + } + } \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/service/JobRequestService.java b/src/main/java/br/edu/utfpr/servicebook/service/JobRequestService.java index 84fdcead..286ba396 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/JobRequestService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/JobRequestService.java @@ -1,6 +1,7 @@ package br.edu.utfpr.servicebook.service; import br.edu.utfpr.servicebook.model.entity.Expertise; +import br.edu.utfpr.servicebook.model.entity.JobImages; import br.edu.utfpr.servicebook.model.entity.JobRequest; import br.edu.utfpr.servicebook.model.entity.User; import br.edu.utfpr.servicebook.model.repository.JobRequestRepository; @@ -13,8 +14,10 @@ import java.sql.Date; import java.time.LocalDate; +import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.Set; @Slf4j @Service @@ -125,4 +128,9 @@ public long countByExpertise(Expertise expertise){ public long countByStatusAndExpertise(JobRequest.Status status, Expertise expertise){ return this.jobRequestRepository.countByStatusAndExpertise(status, expertise); } + + public Set getJobImagesById(Long jobId) { + Optional optionalJobRequest = jobRequestRepository.findById(jobId); + return optionalJobRequest.map(JobRequest::getJobImages).orElse(Collections.emptySet()); + } } \ No newline at end of file diff --git a/src/main/java/br/edu/utfpr/servicebook/service/PaymentService.java b/src/main/java/br/edu/utfpr/servicebook/service/PaymentService.java index 47d109ae..c2d8f25e 100644 --- a/src/main/java/br/edu/utfpr/servicebook/service/PaymentService.java +++ b/src/main/java/br/edu/utfpr/servicebook/service/PaymentService.java @@ -30,7 +30,7 @@ public ResponseEntity pay(Map paymentData){ String apiUrl = "https://api.mercadopago.com/v1/payments"; try { - String accessToken = environment.getProperty("MP_ACCESS_TOKEN"); + String accessToken = environment.getProperty("TEST-2738533774159236-052518-f4e09de99516f8d7b2adb21186313d1b-494777183"); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); diff --git a/src/main/webapp/WEB-INF/tags/banner.tag b/src/main/webapp/WEB-INF/tags/banner.tag index edcd0049..84b343e8 100644 --- a/src/main/webapp/WEB-INF/tags/banner.tag +++ b/src/main/webapp/WEB-INF/tags/banner.tag @@ -13,7 +13,7 @@
        diff --git a/src/main/webapp/WEB-INF/tags/navbar-client.tag b/src/main/webapp/WEB-INF/tags/navbar-client.tag index dbb0b2b3..c8128367 100644 --- a/src/main/webapp/WEB-INF/tags/navbar-client.tag +++ b/src/main/webapp/WEB-INF/tags/navbar-client.tag @@ -10,9 +10,6 @@