Commit 09e16b81 authored by Heber Cordova's avatar Heber Cordova

feat: added business rules

parent 84afc748
...@@ -10,6 +10,24 @@ services: ...@@ -10,6 +10,24 @@ services:
- ./flight-agency-app/nginx.conf:/etc/nginx/conf.d/default.conf - ./flight-agency-app/nginx.conf:/etc/nginx/conf.d/default.conf
networks: networks:
- my-flight-app-network - my-flight-app-network
database:
image: mysql:latest
container_name: flight-booking-db
environment:
- MYSQL_ROOT_PASSWORD=admin
ports:
- "3307:3306"
networks:
- my-flight-app-network
api:
build: ./flight-agency-api
container_name: flight-booking-api
ports:
- "8082:8080"
depends_on:
- database
networks:
- my-flight-app-network
networks: networks:
my-flight-app-network: my-flight-app-network:
...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.agent.controllers; ...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.agent.controllers;
import java.util.List; import java.util.List;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
...@@ -18,6 +19,7 @@ import com.hcordova.flightagencyapi.agent.dto.AgentEditDTO; ...@@ -18,6 +19,7 @@ import com.hcordova.flightagencyapi.agent.dto.AgentEditDTO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@CrossOrigin(origins = "http://localhost:4200")
@RestController @RestController
@RequestMapping("/api/v1/agents") @RequestMapping("/api/v1/agents")
@RequiredArgsConstructor @RequiredArgsConstructor
......
package com.hcordova.flightagencyapi.agent.domain.repositories; package com.hcordova.flightagencyapi.agent.domain.repositories;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
...@@ -10,4 +11,6 @@ import com.hcordova.flightagencyapi.agent.domain.models.Agent; ...@@ -10,4 +11,6 @@ import com.hcordova.flightagencyapi.agent.domain.models.Agent;
@Repository @Repository
public interface AgentRepository extends JpaRepository<Agent, Long>{ public interface AgentRepository extends JpaRepository<Agent, Long>{
Optional<Agent> findByUserId(Long userId); Optional<Agent> findByUserId(Long userId);
Optional<Agent> findByIdAndDeletedAtIsNull(Long id);
List<Agent> findAllByDeletedAtIsNull();
} }
...@@ -21,12 +21,12 @@ public class AgentServiceImpl implements AgentService { ...@@ -21,12 +21,12 @@ public class AgentServiceImpl implements AgentService {
@Override @Override
public List<Agent> getAll() { public List<Agent> getAll() {
return agentRepository.findAll(); return agentRepository.findAllByDeletedAtIsNull();
} }
@Override @Override
public Agent getById(Long id) { public Agent getById(Long id) {
return agentRepository.findById(id) return agentRepository.findByIdAndDeletedAtIsNull(id)
.orElseThrow(() -> new NotFoundException("Agent not found")); .orElseThrow(() -> new NotFoundException("Agent not found"));
} }
......
...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.aircraft.controllers; ...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.aircraft.controllers;
import java.util.List; import java.util.List;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
...@@ -12,6 +13,7 @@ import com.hcordova.flightagencyapi.aircraft.dto.AircraftDTO; ...@@ -12,6 +13,7 @@ import com.hcordova.flightagencyapi.aircraft.dto.AircraftDTO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping("/api/v1/aircrafts") @RequestMapping("/api/v1/aircrafts")
@RequiredArgsConstructor @RequiredArgsConstructor
......
...@@ -6,4 +6,5 @@ import com.hcordova.flightagencyapi.aircraft.domain.models.Aircraft; ...@@ -6,4 +6,5 @@ import com.hcordova.flightagencyapi.aircraft.domain.models.Aircraft;
public interface AircraftService { public interface AircraftService {
List<Aircraft> getAll(); List<Aircraft> getAll();
Aircraft getById(Long id);
} }
...@@ -20,4 +20,10 @@ public class AircraftServiceImpl implements AircraftService { ...@@ -20,4 +20,10 @@ public class AircraftServiceImpl implements AircraftService {
public List<Aircraft> getAll() { public List<Aircraft> getAll() {
return aircraftRepository.findAll(); return aircraftRepository.findAll();
} }
@Override
public Aircraft getById(Long id) {
return aircraftRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Aircraft not found"));
}
} }
...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.airline.controllers; ...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.airline.controllers;
import java.util.List; import java.util.List;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
...@@ -12,6 +13,7 @@ import com.hcordova.flightagencyapi.airline.dto.AirlineDTO; ...@@ -12,6 +13,7 @@ import com.hcordova.flightagencyapi.airline.dto.AirlineDTO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping("/api/v1/airlines") @RequestMapping("/api/v1/airlines")
@RequiredArgsConstructor @RequiredArgsConstructor
......
...@@ -8,6 +8,7 @@ import jakarta.persistence.Id; ...@@ -8,6 +8,7 @@ import jakarta.persistence.Id;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@Entity @Entity
...@@ -15,6 +16,7 @@ import lombok.Setter; ...@@ -15,6 +16,7 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor
public class Airline { public class Airline {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
......
...@@ -6,4 +6,5 @@ import com.hcordova.flightagencyapi.airline.domain.models.Airline; ...@@ -6,4 +6,5 @@ import com.hcordova.flightagencyapi.airline.domain.models.Airline;
public interface AirlineService { public interface AirlineService {
List<Airline> getAll(); List<Airline> getAll();
Airline getById(Long id);
} }
...@@ -7,6 +7,7 @@ import org.springframework.stereotype.Service; ...@@ -7,6 +7,7 @@ import org.springframework.stereotype.Service;
import com.hcordova.flightagencyapi.airline.domain.models.Airline; import com.hcordova.flightagencyapi.airline.domain.models.Airline;
import com.hcordova.flightagencyapi.airline.domain.repositories.AirlineRepository; import com.hcordova.flightagencyapi.airline.domain.repositories.AirlineRepository;
import com.hcordova.flightagencyapi.airline.domain.services.AirlineService; import com.hcordova.flightagencyapi.airline.domain.services.AirlineService;
import com.hcordova.flightagencyapi.shared.exceptions.NotFoundException;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
...@@ -19,4 +20,10 @@ public class AirlineServiceImpl implements AirlineService{ ...@@ -19,4 +20,10 @@ public class AirlineServiceImpl implements AirlineService{
public List<Airline> getAll() { public List<Airline> getAll() {
return this.airlineRepository.findAll(); return this.airlineRepository.findAll();
} }
@Override
public Airline getById(Long id) {
return this.airlineRepository.findById(id)
.orElseThrow(() -> new NotFoundException("Airline not found"));
}
} }
...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.airport.controllers; ...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.airport.controllers;
import java.util.List; import java.util.List;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
...@@ -12,6 +13,7 @@ import com.hcordova.flightagencyapi.airport.dto.AirportDTO; ...@@ -12,6 +13,7 @@ import com.hcordova.flightagencyapi.airport.dto.AirportDTO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping("/api/v1/airports") @RequestMapping("/api/v1/airports")
@RequiredArgsConstructor @RequiredArgsConstructor
......
...@@ -6,4 +6,5 @@ import com.hcordova.flightagencyapi.airport.domain.models.Airport; ...@@ -6,4 +6,5 @@ import com.hcordova.flightagencyapi.airport.domain.models.Airport;
public interface AirportService { public interface AirportService {
List<Airport> getAll(); List<Airport> getAll();
Airport getById(Long id);
} }
...@@ -7,6 +7,7 @@ import org.springframework.stereotype.Service; ...@@ -7,6 +7,7 @@ import org.springframework.stereotype.Service;
import com.hcordova.flightagencyapi.airport.domain.models.Airport; import com.hcordova.flightagencyapi.airport.domain.models.Airport;
import com.hcordova.flightagencyapi.airport.domain.repositories.AirportRepository; import com.hcordova.flightagencyapi.airport.domain.repositories.AirportRepository;
import com.hcordova.flightagencyapi.airport.domain.services.AirportService; import com.hcordova.flightagencyapi.airport.domain.services.AirportService;
import com.hcordova.flightagencyapi.shared.exceptions.NotFoundException;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
...@@ -20,4 +21,10 @@ public class AirportServiceImpl implements AirportService { ...@@ -20,4 +21,10 @@ public class AirportServiceImpl implements AirportService {
public List<Airport> getAll() { public List<Airport> getAll() {
return airportRepository.findAll(); return airportRepository.findAll();
} }
@Override
public Airport getById(Long id) {
return airportRepository.findById(id)
.orElseThrow(() -> new NotFoundException(String.format("Airport with id %d not found", id)));
}
} }
package com.hcordova.flightagencyapi.flight.controllers;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.hcordova.flightagencyapi.flight.domain.services.FlightScheduleService;
import com.hcordova.flightagencyapi.flight.dto.FlightAllDTO;
import com.hcordova.flightagencyapi.flight.dto.FlightByDTO;
import com.hcordova.flightagencyapi.flight.dto.FlightSaveDTO;
import com.hcordova.flightagencyapi.flight.dto.FlightSearchDTO;
import lombok.RequiredArgsConstructor;
@CrossOrigin(origins = "*")
@RestController
@RequestMapping("/api/v1/flights")
@RequiredArgsConstructor
public class FlightScheduleController {
private final FlightScheduleService flightScheduleService;
@GetMapping()
public ResponseEntity<List<FlightAllDTO>> getAll() {
System.out.print("getAll");
return ResponseEntity.ok(flightScheduleService.getAll().stream().map(flight -> {
return new FlightAllDTO(flight);
}).toList());
}
@GetMapping("{id}")
public ResponseEntity<FlightByDTO> getById(@PathVariable Long id) {
return ResponseEntity.ok(new FlightByDTO(flightScheduleService.getById(id)));
}
@GetMapping("/search")
public ResponseEntity<List<FlightSearchDTO>> searchFlight(@RequestParam(name = "airportOriginId") Long origin,
@RequestParam(name = "airportDestinationId") Long destination, @RequestParam(name = "startDate") String startDate) {
return ResponseEntity.ok(flightScheduleService.searchByOriginDestinationAndDate(origin, destination, startDate).stream().map(flight -> new FlightSearchDTO(flight, startDate)).toList());
}
@PostMapping
public ResponseEntity<FlightAllDTO> save(@RequestBody FlightSaveDTO saveDTO) {
return ResponseEntity.ok(new FlightAllDTO(flightScheduleService.save(saveDTO)));
}
@DeleteMapping("{id}")
public ResponseEntity<FlightAllDTO> delete(@PathVariable Long id) {
return ResponseEntity.ok(new FlightAllDTO(flightScheduleService.delete(id)));
}
}
package com.hcordova.flightagencyapi.flight.domain.models;
import java.time.LocalDate;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "flight_costs")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class FlightCost {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)
@JoinColumn(name = "flight_schedule_id", nullable = false, updatable = false)
private FlightSchedule flightSchedule;
@Column(nullable = false)
@Temporal(TemporalType.DATE)
private LocalDate dateStart;
@Column(nullable = false)
@Temporal(TemporalType.DATE)
private LocalDate dateEnd;
@Column(nullable = false, columnDefinition = "DECIMAL(10,2)")
private Double cost;
}
package com.hcordova.flightagencyapi.flight.domain.models;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import com.hcordova.flightagencyapi.aircraft.domain.models.Aircraft;
import com.hcordova.flightagencyapi.airline.domain.models.Airline;
import com.hcordova.flightagencyapi.airport.domain.models.Airport;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "flight_schedules")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class FlightSchedule implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Airline airline;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Aircraft aircraft;
@ManyToOne(optional = false)
@JoinColumn(name = "airport_origin_id", referencedColumnName = "id")
@Access(AccessType.FIELD)
private Airport airportOrigin;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Airport airportDestination;
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime departureDateTime;
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime arrivalDateTime;
@OneToMany(mappedBy = "flightSchedule", cascade = CascadeType.ALL)
List<Leg> legs;
@OneToMany(mappedBy = "flightSchedule", cascade = CascadeType.ALL)
List<FlightCost> costs;
@Column(nullable = true)
@Temporal(TemporalType.DATE)
public LocalDate deletedAt;
}
package com.hcordova.flightagencyapi.flight.domain.models;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import com.hcordova.flightagencyapi.airport.domain.models.Airport;
import com.hcordova.flightagencyapi.reservation.domain.models.Reservation;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "legs")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Leg {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)
@JoinColumn(name = "flight_schedule_id", nullable = false, updatable = false)
private FlightSchedule flightSchedule;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "airport_origin_id", nullable = false, updatable = false)
private Airport airportOrigin;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "airport_destination_id", nullable = false, updatable = false)
private Airport airportDestination;
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime actualDeparture;
@Column(nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime actualArrival;
@ManyToMany(cascade = CascadeType.ALL)
private List<Reservation> reservations = new ArrayList<>();
}
package com.hcordova.flightagencyapi.flight.domain.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.hcordova.flightagencyapi.flight.domain.models.FlightCost;
@Repository
public interface FlightCostRepository extends JpaRepository<FlightCost, Long> {
}
package com.hcordova.flightagencyapi.flight.domain.repositories;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import com.hcordova.flightagencyapi.flight.domain.models.FlightSchedule;
@Repository
public interface FlightScheduleRepository extends JpaRepository<FlightSchedule, Long> {
List<FlightSchedule> findAllByDeletedAtIsNull();
List<FlightSchedule> findByAirportOrigin_Id(Long airportOriginId);
@Query("SELECT fs FROM FlightSchedule fs WHERE fs.airportOrigin.id = ?1 AND fs.airportDestination.id = ?2 AND (?3 between fs.departureDateTime AND fs.arrivalDateTime) AND fs.deletedAt IS NULL")
List<FlightSchedule> searchFlight(Long airportOriginId, Long airportDestinationId, LocalDateTime startDate);
Optional<FlightSchedule> findByIdAndDeletedAtIsNull(Long id);
}
package com.hcordova.flightagencyapi.flight.domain.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.hcordova.flightagencyapi.flight.domain.models.Leg;
@Repository
public interface LegRepository extends JpaRepository<Leg, Long> {
}
package com.hcordova.flightagencyapi.flight.domain.services;
import java.util.List;
import com.hcordova.flightagencyapi.flight.domain.models.FlightCost;
public interface FlightCostService {
List<FlightCost> getAll();
FlightCost getById(Long id);
}
package com.hcordova.flightagencyapi.flight.domain.services;
import java.util.List;
import com.hcordova.flightagencyapi.flight.domain.models.FlightSchedule;
import com.hcordova.flightagencyapi.flight.dto.FlightSaveDTO;
public interface FlightScheduleService {
List<FlightSchedule> getAll();
List<FlightSchedule> searchByOriginDestinationAndDate(Long airportOriginId, Long airportDestinationId, String startDate);
FlightSchedule getById(Long id);
FlightSchedule save(FlightSaveDTO saveDTO);
FlightSchedule delete(Long id);
}
package com.hcordova.flightagencyapi.flight.domain.services;
import java.util.List;
import com.hcordova.flightagencyapi.flight.domain.models.Leg;
import com.hcordova.flightagencyapi.flight.dto.LegSaveDTO;
public interface LegService {
List<Leg> getAll();
List<Leg> saveAll(List<LegSaveDTO> legs);
}
package com.hcordova.flightagencyapi.flight.dto;
import java.time.LocalDateTime;
import com.hcordova.flightagencyapi.flight.domain.models.FlightSchedule;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class FlightAllDTO {
private Long id;
private String airportOrigin;
private String airportDestination;
private LocalDateTime departureDate;
private LocalDateTime arrivalDate;
public FlightAllDTO(FlightSchedule flightSchedule) {
this.id = flightSchedule.getId();
this.airportOrigin = flightSchedule.getAirportOrigin().getName();
this.airportDestination = flightSchedule.getAirportDestination().getName();
this.departureDate = flightSchedule.getDepartureDateTime();
this.arrivalDate = flightSchedule.getArrivalDateTime();
}
}
package com.hcordova.flightagencyapi.flight.dto;
import java.util.List;
import com.hcordova.flightagencyapi.flight.domain.models.FlightSchedule;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class FlightByDTO {
private Long id;
private String airline;
private Long airlineId;
private String aircraft;
private Long aircraftId;
private String departureDate;
private String arrivalDate;
private List<LegDTO> legs;
private List<FlightCostDTO> costs;
public FlightByDTO(FlightSchedule flightSchedule) {
this.id = flightSchedule.getId();
this.departureDate = flightSchedule.getDepartureDateTime().toLocalDate().toString();
this.arrivalDate = flightSchedule.getArrivalDateTime().toLocalDate().toString();
this.airline = flightSchedule.getAirline().getName();
this.airlineId = flightSchedule.getAirline().getId();
this.aircraft = flightSchedule.getAircraft().getName();
this.aircraftId = flightSchedule.getAircraft().getId();
this.legs = flightSchedule.getLegs().stream().map(leg -> {
return new LegDTO(leg);
}).toList();
this.costs = flightSchedule.getCosts().stream().map(cost -> {
return new FlightCostDTO(cost);
}).toList();
}
}
package com.hcordova.flightagencyapi.flight.dto;
import com.hcordova.flightagencyapi.flight.domain.models.FlightCost;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class FlightCostDTO {
private Long id;
private String dateStart;
private String dateEnd;
private Double cost;
public FlightCostDTO(FlightCost flightCost) {
this.id = flightCost.getId();
this.dateStart = flightCost.getDateStart().toString();
this.dateEnd = flightCost.getDateEnd().toString();
this.cost = flightCost.getCost();
}
}
package com.hcordova.flightagencyapi.flight.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class FlightCostSaveDTO {
private Long aircraftId;
private String dateStart;
private String dateEnd;
private Double cost;
}
package com.hcordova.flightagencyapi.flight.dto;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class FlightSaveDTO {
private Long airlineId;
private Long aircraftId;
private String departureDate;
private String arrivalDate;
private List<LegSaveDTO> legs;
private List<FlightCostSaveDTO> costs;
}
package com.hcordova.flightagencyapi.flight.dto;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import com.hcordova.flightagencyapi.flight.domain.models.FlightCost;
import com.hcordova.flightagencyapi.flight.domain.models.FlightSchedule;
import com.hcordova.flightagencyapi.flight.domain.models.Leg;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class FlightSearchDTO {
private Long id;
private String airline;
private String aircraft;
private String airportOrigin;
private String airportDestination;
private String flightType;
private String departureDate;
private String arrivalDate;
private Double price;
private List<LegDTO> legs;
public FlightSearchDTO(FlightSchedule flightSchedule, String startDate) {
this.id = flightSchedule.getId();
LocalDate dateToCheck = LocalDate.parse(startDate);
FlightCost flightCost = new FlightCost();
for (FlightCost cost : flightSchedule.getCosts()) {
if ((dateToCheck.isAfter(cost.getDateStart()) && dateToCheck.isBefore(cost.getDateEnd())) ||
dateToCheck.isEqual(cost.getDateStart()) || dateToCheck.isEqual(cost.getDateEnd())) {
flightCost = cost;
}
}
this.airportOrigin = flightSchedule.getAirportOrigin().getName();
this.airportDestination = flightSchedule.getAirportDestination().getName();
LocalDateTime legDeparture = flightSchedule.getLegs().stream().findFirst().get().getActualDeparture();
LocalDateTime legArrival = flightSchedule.getLegs().get(flightSchedule.getLegs().size() - 1).getActualArrival();
Duration duration = java.time.Duration.between(legDeparture, legArrival);
LocalDateTime departureDateTime = LocalDateTime.of(LocalDate.parse(startDate), flightSchedule.getDepartureDateTime().toLocalTime());
LocalDateTime arrivalDateTime = departureDateTime.plus(duration);
calculateDates(flightSchedule.getLegs(), startDate);
this.departureDate = departureDateTime.toString();
this.arrivalDate = arrivalDateTime.toString();
this.airline = flightSchedule.getAirline().getName();
this.aircraft = flightSchedule.getAircraft().getName();
this.flightType = flightSchedule.getLegs().size() > 1 ? "Round Trip" : "One Way";
this.price = flightCost.getCost();
this.legs = flightSchedule.getLegs().stream().map(leg -> {
return new LegDTO(leg);
}).toList();
}
private void calculateDates(List<Leg> legs, String startDate) {
LocalDate start = LocalDate.parse(startDate);
for (int i = 0; i < legs.size(); i++) {
Leg leg = legs.get(i);
if (i == 0) {
leg.setActualDeparture(LocalDateTime.of(start, leg.getActualDeparture().toLocalTime()));
leg.setActualArrival(LocalDateTime.of(start, leg.getActualArrival().toLocalTime()));
} else {
Duration durationDeparture = Duration.between(leg.getActualDeparture(), legs.get(i - 1).getActualArrival());
Duration durationArrival = Duration.between(leg.getActualDeparture(), leg.getActualArrival());
leg.setActualArrival(leg.getActualDeparture().plus(durationArrival));
leg.setActualDeparture(legs.get(i - 1).getActualArrival().plus(durationDeparture));
}
}
}
}
package com.hcordova.flightagencyapi.flight.dto;
import com.hcordova.flightagencyapi.flight.domain.models.Leg;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class LegDTO {
private Long id;
private String airportOrigin;
private String airportDestination;
private String departureDateTime;
private String arrivalDateTime;
public LegDTO(Leg leg) {
this.id = leg.getId();
this.airportOrigin = leg.getAirportOrigin().getName();
this.airportDestination = leg.getAirportDestination().getName();
this.departureDateTime = leg.getActualDeparture().toString();
this.arrivalDateTime = leg.getActualArrival().toString();
}
}
package com.hcordova.flightagencyapi.flight.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class LegSaveDTO {
private Long airportOriginId;
private Long airportDestinationId;
private String departureDateTime;
private String arrivalDateTime;
}
package com.hcordova.flightagencyapi.flight.services;
import java.util.List;
import org.springframework.stereotype.Service;
import com.hcordova.flightagencyapi.flight.domain.models.FlightCost;
import com.hcordova.flightagencyapi.flight.domain.repositories.FlightCostRepository;
import com.hcordova.flightagencyapi.flight.domain.services.FlightCostService;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class FlightCostServiceImpl implements FlightCostService {
private final FlightCostRepository flightCostRepository;
@Override
public List<FlightCost> getAll() {
return flightCostRepository.findAll();
}
@Override
public FlightCost getById(Long id) {
return null;
}
}
package com.hcordova.flightagencyapi.flight.services;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.ResponseBody;
import com.hcordova.flightagencyapi.aircraft.domain.services.AircraftService;
import com.hcordova.flightagencyapi.airline.domain.services.AirlineService;
import com.hcordova.flightagencyapi.airport.domain.models.Airport;
import com.hcordova.flightagencyapi.airport.domain.services.AirportService;
import com.hcordova.flightagencyapi.flight.domain.models.FlightCost;
import com.hcordova.flightagencyapi.flight.domain.models.FlightSchedule;
import com.hcordova.flightagencyapi.flight.domain.models.Leg;
import com.hcordova.flightagencyapi.flight.domain.repositories.FlightScheduleRepository;
import com.hcordova.flightagencyapi.flight.domain.services.FlightScheduleService;
import com.hcordova.flightagencyapi.flight.dto.FlightSaveDTO;
import com.hcordova.flightagencyapi.shared.exceptions.NotFoundException;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class FlightScheduleServiceImpl implements FlightScheduleService{
private final FlightScheduleRepository flightScheduleRepository;
private final AirlineService airlineService;
private final AircraftService aircraftService;
private final AirportService airportService;
@Override
public List<FlightSchedule> getAll() {
return flightScheduleRepository.findAllByDeletedAtIsNull();
}
@Override
public FlightSchedule save(FlightSaveDTO saveDTO) {
FlightSchedule flightSchedule = new FlightSchedule();
// Set airline and aircraft
flightSchedule.setAirline(airlineService.getById(saveDTO.getAirlineId()));
flightSchedule.setAircraft(aircraftService.getById(saveDTO.getAircraftId()));
// Valid legs size
if (saveDTO.getLegs().size() == 0)
throw new RuntimeException("Invalid legs size");
if (saveDTO.getCosts().size() == 0)
throw new RuntimeException("Invalid costs size");
List<Leg> legsToSave = saveDTO.getLegs().stream().map(leg -> {
Airport airportOrigin = airportService.getById(leg.getAirportOriginId());
Airport airportDestination = airportService.getById(leg.getAirportDestinationId());
try {
LocalDateTime departureDateTime = LocalDateTime.parse(leg.getDepartureDateTime());
LocalDateTime arrivalDateTime = LocalDateTime.parse(leg.getArrivalDateTime());
return new Leg(null, flightSchedule, airportOrigin, airportDestination, departureDateTime, arrivalDateTime, null);
} catch (Exception e) {
throw new RuntimeException("Invalid date format 1");
}
}).toList();
List<FlightCost> costsToSave = saveDTO.getCosts().stream().map(cost -> {
try {
LocalDate validFrontDate = LocalDate.parse(cost.getDateStart());
LocalDate validToDate = LocalDate.parse(cost.getDateEnd());
return new FlightCost(null, flightSchedule, validFrontDate, validToDate, cost.getCost());
} catch (Exception e) {
throw new RuntimeException("Invalid date format 2");
}
}).toList();
// Set departure and arrival date
try {
LocalDateTime departureDate = LocalDateTime.of(LocalDate.parse(saveDTO.getDepartureDate()), legsToSave.get(0).getActualDeparture().toLocalTime());
LocalDateTime arrivalDate = LocalDateTime.of(LocalDate.parse(saveDTO.getArrivalDate()), legsToSave.get(legsToSave.size() - 1).getActualArrival().toLocalTime());
flightSchedule.setDepartureDateTime(departureDate);
flightSchedule.setArrivalDateTime(arrivalDate);
} catch (Exception e) {
throw new RuntimeException("Invalid date format 3");
}
// Set airport origin and destination
flightSchedule.setAirportOrigin(legsToSave.get(0).getAirportOrigin());
flightSchedule.setAirportDestination(legsToSave.get(legsToSave.size() - 1).getAirportDestination());
// Save legs and costs
flightSchedule.setLegs(legsToSave);
flightSchedule.setCosts(costsToSave);
return flightScheduleRepository.save(flightSchedule);
}
@Override
public FlightSchedule getById(Long id) {
return flightScheduleRepository.findByIdAndDeletedAtIsNull(id)
.orElseThrow(() -> new NotFoundException(String.format("Flight with id %d not found", id)));
}
@Override
public FlightSchedule delete(Long id) {
FlightSchedule flightSchedule = getById(id);
flightSchedule.setDeletedAt(LocalDate.now());
return flightScheduleRepository.save(flightSchedule);
}
@Override
@ResponseBody
public List<FlightSchedule> searchByOriginDestinationAndDate(Long airportOriginId, Long airportDestinationId,
String startDate) {
LocalDate date = LocalDate.parse(startDate);
LocalDateTime dateTime = date.atStartOfDay();
return flightScheduleRepository.searchFlight(airportOriginId, airportDestinationId, dateTime);
}
}
package com.hcordova.flightagencyapi.flight.services;
import java.util.List;
import org.springframework.stereotype.Service;
import com.hcordova.flightagencyapi.flight.domain.models.Leg;
import com.hcordova.flightagencyapi.flight.domain.repositories.LegRepository;
import com.hcordova.flightagencyapi.flight.domain.services.LegService;
import com.hcordova.flightagencyapi.flight.dto.LegSaveDTO;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class LegServiceImpl implements LegService{
private final LegRepository legRepository;
@Override
public List<Leg> getAll() {
return legRepository.findAll();
}
@Override
public List<Leg> saveAll(List<LegSaveDTO> legs) {
// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// List<Leg> legsToSave = legs.stream().map(leg -> {
// Airport airportOrigin = airportService.getById(leg.getAirportOriginId());
// Airport airportDestination = airportService.getById(leg.getAirportDestinationId());
// LocalDateTime departureDateTime = LocalDateTime.parse(leg.getDepartureDateTime(), formatter);
// LocalDateTime arrivalDateTime = LocalDateTime.parse(leg.getArrivalDateTime(), formatter);
// return new Leg(null, airportOrigin, airportDestination, departureDateTime, arrivalDateTime);
// }).toList();
// return legRepository.saveAll(legs);
return null;
}
}
...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.passenger.controllers; ...@@ -3,6 +3,7 @@ package com.hcordova.flightagencyapi.passenger.controllers;
import java.util.List; import java.util.List;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
...@@ -18,6 +19,7 @@ import com.hcordova.flightagencyapi.passenger.dto.PassengerTableDTO; ...@@ -18,6 +19,7 @@ import com.hcordova.flightagencyapi.passenger.dto.PassengerTableDTO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping("/api/v1/passengers") @RequestMapping("/api/v1/passengers")
@RequiredArgsConstructor @RequiredArgsConstructor
...@@ -27,8 +29,7 @@ public class PassengerController { ...@@ -27,8 +29,7 @@ public class PassengerController {
@GetMapping @GetMapping
public ResponseEntity<List<PassengerTableDTO>> getAll() { public ResponseEntity<List<PassengerTableDTO>> getAll() {
return ResponseEntity.ok(passengerService.getAll().stream().map(passenger -> { return ResponseEntity.ok(passengerService.getAll().stream().map(passenger -> {
return new PassengerTableDTO(passenger.getId(), passenger.getUser().getName(), passenger.getUser().getLastname(), return new PassengerTableDTO(passenger);
passenger.getCountry(), passenger.getCity());
}).toList()); }).toList());
} }
......
package com.hcordova.flightagencyapi.passenger.domain.repositories; package com.hcordova.flightagencyapi.passenger.domain.repositories;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
...@@ -9,4 +10,6 @@ import com.hcordova.flightagencyapi.passenger.domain.models.Passenger; ...@@ -9,4 +10,6 @@ import com.hcordova.flightagencyapi.passenger.domain.models.Passenger;
public interface PassengerRepository extends JpaRepository<Passenger, Long>{ public interface PassengerRepository extends JpaRepository<Passenger, Long>{
Optional<Passenger> findByUserId(Long userId); Optional<Passenger> findByUserId(Long userId);
List<Passenger> findAllByDeletedAtIsNull();
Optional<Passenger> findByIdAndDeletedAtIsNull(Long id);
} }
package com.hcordova.flightagencyapi.passenger.dto; package com.hcordova.flightagencyapi.passenger.dto;
import com.hcordova.flightagencyapi.passenger.domain.models.Passenger;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
...@@ -11,6 +13,20 @@ public class PassengerTableDTO { ...@@ -11,6 +13,20 @@ public class PassengerTableDTO {
private Long id; private Long id;
private String name; private String name;
private String lastname; private String lastname;
private String fullname;
private String country; private String country;
private String city; private String city;
private String phone;
private String email;
public PassengerTableDTO(Passenger passenger) {
this.id = passenger.getId();
this.name = passenger.getUser().getName();
this.lastname = passenger.getUser().getLastname();
this.fullname = passenger.getUser().getName() + " " + passenger.getUser().getLastname();
this.country = passenger.getCountry();
this.city = passenger.getCity();
this.phone = passenger.getPhone();
this.email = passenger.getUser().getEmail();
}
} }
...@@ -21,12 +21,12 @@ public class PassengerServiceImpl implements PassengerService { ...@@ -21,12 +21,12 @@ public class PassengerServiceImpl implements PassengerService {
@Override @Override
public List<Passenger> getAll() { public List<Passenger> getAll() {
return passengerRepository.findAll(); return passengerRepository.findAllByDeletedAtIsNull();
} }
@Override @Override
public Passenger getById(Long id) { public Passenger getById(Long id) {
return passengerRepository.findById(id) return passengerRepository.findByIdAndDeletedAtIsNull(id)
.orElseThrow(() -> new NotFoundException("Passenger not found")); .orElseThrow(() -> new NotFoundException("Passenger not found"));
} }
......
package com.hcordova.flightagencyapi.reservation.controllers;
import java.util.List;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.hcordova.flightagencyapi.reservation.domain.services.ReservationService;
import com.hcordova.flightagencyapi.reservation.dto.ReservationDTO;
import com.hcordova.flightagencyapi.reservation.dto.ReservationExtendedDTO;
import com.hcordova.flightagencyapi.reservation.dto.ReservationPassengerDTO;
import com.hcordova.flightagencyapi.reservation.dto.ReservationSaveDTO;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping("/api/v1/reservations")
@RequiredArgsConstructor
public class ReservationController {
private final ReservationService reservationService;
@GetMapping
public List<ReservationDTO> getAll() {
return reservationService.getAll().stream().map(reservation -> {
return new ReservationDTO(reservation);
}).toList();
}
@GetMapping("/passenger/{id}")
public List<ReservationPassengerDTO> getByPassengerId(@PathVariable Long id) {
return reservationService.getByPassengerId(id).stream().map(reservation -> {
return new ReservationPassengerDTO(reservation);
}).toList();
}
@PutMapping("/pay/{id}")
public ReservationPassengerDTO payReservation(@PathVariable Long id) {
return new ReservationPassengerDTO(reservationService.payReservation(id));
}
@GetMapping("{id}")
public ReservationExtendedDTO getById(@PathVariable Long id) {
return new ReservationExtendedDTO(reservationService.getById(id));
}
@PostMapping
public ReservationDTO save(@RequestBody ReservationSaveDTO reservationDTO) {
return new ReservationDTO(reservationService.save(reservationDTO));
}
@PutMapping("/cancel/{id}")
public ReservationDTO cancelReservation(@PathVariable Long id) {
return new ReservationDTO(reservationService.cancelReservation(id));
}
@DeleteMapping("{id}")
public ReservationDTO delete(@PathVariable Long id) {
return new ReservationDTO(reservationService.deleteReservation(id));
}
}
package com.hcordova.flightagencyapi.reservation.controllers;
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.hcordova.flightagencyapi.reservation.domain.services.TicketTypeService;
import com.hcordova.flightagencyapi.reservation.dto.TicketTypeDTO;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping("/api/v1/ticket-types")
@RequiredArgsConstructor
public class TicketTypeController {
private final TicketTypeService ticketTypeService;
@GetMapping
public List<TicketTypeDTO> getAll() {
return ticketTypeService.getAll().stream().map(ticketType -> {
return new TicketTypeDTO(ticketType);
}).toList();
}
}
package com.hcordova.flightagencyapi.reservation.controllers;
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.hcordova.flightagencyapi.reservation.domain.services.TravelClassService;
import com.hcordova.flightagencyapi.reservation.dto.TravelClassDTO;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping("/api/v1/travel-classes")
@RequiredArgsConstructor
public class TravelClassController {
private final TravelClassService travelClassService;
@GetMapping
public List<TravelClassDTO> getAll() {
return travelClassService.getAll().stream().map(travelClass -> {
return new TravelClassDTO(travelClass);
}).toList();
}
}
package com.hcordova.flightagencyapi.reservation.domain.models;
import java.time.LocalDate;
import com.hcordova.flightagencyapi.payment.domain.models.PaymentStatus;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "payments")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Payment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false)
private PaymentStatus status;
@Column(nullable = false)
@Temporal(TemporalType.DATE)
private LocalDate date;
@Column(nullable = false, columnDefinition = "DECIMAL(10,2)")
private Double amount;
}
package com.hcordova.flightagencyapi.reservation.domain.models;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import com.hcordova.flightagencyapi.agent.domain.models.Agent;
import com.hcordova.flightagencyapi.flight.domain.models.Leg;
import com.hcordova.flightagencyapi.passenger.domain.models.Passenger;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "reservations")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Reservation {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Agent agent;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Passenger passenger;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private ReservationStatus status;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private TicketType ticketType;
@ManyToOne(optional = false, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private TravelClass travelClass;
@Column(nullable = false)
@Temporal(TemporalType.DATE)
private LocalDate createdAt;
@OneToOne(optional = false, cascade = CascadeType.ALL)
private Payment payment;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "reservations_legs",
joinColumns = @JoinColumn(name = "reservation_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "leg_id", referencedColumnName = "id"))
private List<Leg> legs = new ArrayList<>();
@Column(nullable = true)
@Temporal(TemporalType.DATE)
private LocalDate deletedAt;
}
package com.hcordova.flightagencyapi.reservation.domain.models;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "ticket_type")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class TicketType {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 30, unique = true)
private String name;
}
package com.hcordova.flightagencyapi.reservation.domain.models;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "travel_class")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class TravelClass {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 30, unique = true)
private String name;
}
package com.hcordova.flightagencyapi.reservation.domain.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.hcordova.flightagencyapi.reservation.domain.models.Payment;
@Repository
public interface PaymentRepository extends JpaRepository<Payment, Long> {
}
package com.hcordova.flightagencyapi.reservation.domain.repositories;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.hcordova.flightagencyapi.reservation.domain.models.Reservation;
@Repository
public interface ReservationsRepository extends JpaRepository<Reservation, Long> {
List<Reservation> findByDeletedAtIsNullAndPassenger_Id(Long passengerId);
List<Reservation> findByDeletedAtIsNull();
Optional<Reservation> findByIdAndDeletedAtIsNull(Long id);
}
package com.hcordova.flightagencyapi.reservation.domain.repositories;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.hcordova.flightagencyapi.reservation.domain.models.TicketType;
@Repository
public interface TicketTypeRepository extends JpaRepository<TicketType, Long>{
Optional<TicketType> findById(Long id);
}
package com.hcordova.flightagencyapi.reservation.domain.repositories;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.hcordova.flightagencyapi.reservation.domain.models.TravelClass;
@Repository
public interface TravelClassRepository extends JpaRepository<TravelClass, Long> {
Optional<TravelClass> findById(Long id);
}
package com.hcordova.flightagencyapi.reservation.domain.services;
import java.util.List;
import com.hcordova.flightagencyapi.reservation.domain.models.Reservation;
import com.hcordova.flightagencyapi.reservation.dto.ReservationSaveDTO;
public interface ReservationService {
List<Reservation> getAll();
Reservation getById(Long id);
List<Reservation> getByPassengerId(Long id);
Reservation save(ReservationSaveDTO reservationDTO);
Reservation payReservation(Long id);
Reservation cancelReservation(Long id);
Reservation deleteReservation(Long id);
}
package com.hcordova.flightagencyapi.reservation.domain.services;
import java.util.List;
import com.hcordova.flightagencyapi.reservation.domain.models.TicketType;
public interface TicketTypeService {
List<TicketType> getAll();
TicketType getById(Long id);
}
package com.hcordova.flightagencyapi.reservation.domain.services;
import java.util.List;
import com.hcordova.flightagencyapi.reservation.domain.models.TravelClass;
public interface TravelClassService {
List<TravelClass> getAll();
TravelClass getById(Long id);
}
package com.hcordova.flightagencyapi.reservation.dto;
import com.hcordova.flightagencyapi.reservation.domain.models.Reservation;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ReservationDTO {
private Long id;
private String passenger;
private String ticketType;
private String travelClass;
private String status;
public ReservationDTO(Reservation reservation) {
this.id = reservation.getId();
this.passenger = reservation.getPassenger().getUser().getName() + " " + reservation.getPassenger().getUser().getLastname();
this.ticketType = reservation.getTicketType().getName();
this.travelClass = reservation.getTravelClass().getName();
this.status = convertStatus(reservation.getStatus().getName());
}
private String convertStatus(String status) {
switch (status.toLowerCase()) {
case "registered":
return "Registrado";
case "processing_payment":
return "Procesando pago";
case "paid":
return "Pagado";
case "cancelled":
return "Cancelado";
default:
return "";
}
}
}
package com.hcordova.flightagencyapi.reservation.dto;
import java.util.List;
import com.hcordova.flightagencyapi.flight.dto.LegDTO;
import com.hcordova.flightagencyapi.reservation.domain.models.Reservation;
import lombok.Getter;
@Getter
public class ReservationExtendedDTO {
private Long id;
private Long passengerId;
private String passenger;
private String ticketType;
private Long airportOriginId;
private String airportOrigin;
private Long airportDestinationId;
private String airportDestination;
private String departureDate;
private Long ticketTypeId;
private String travelClass;
private Long travelClassId;
private Long flightId;
private String status;
List<LegDTO> legs;
public ReservationExtendedDTO(Reservation reservation) {
this.id = reservation.getId();
this.passengerId = reservation.getPassenger().getId();
this.passenger = reservation.getPassenger().getUser().getName() + " " + reservation.getPassenger().getUser().getLastname();
this.ticketType = reservation.getTicketType().getName();
this.ticketTypeId = reservation.getTicketType().getId();
this.airportOriginId = reservation.getLegs().get(0).getFlightSchedule().getAirportOrigin().getId();
this.airportDestinationId = reservation.getLegs().get(0).getFlightSchedule().getAirportDestination().getId();
this.departureDate = reservation.getLegs().get(0).getFlightSchedule().getDepartureDateTime().toLocalDate().toString();
this.travelClass = reservation.getTravelClass().getName();
this.travelClassId = reservation.getTravelClass().getId();
this.airportOrigin = reservation.getLegs().get(0).getFlightSchedule().getAirportOrigin().getName();
this.airportDestination = reservation.getLegs().get(0).getFlightSchedule().getAirportDestination().getName();
this.status = convertStatus(reservation.getStatus().getName());
this.flightId = reservation.getLegs().get(0).getFlightSchedule().getId();
this.legs = reservation.getLegs().stream().map(leg -> {
return new LegDTO(leg);
}).toList();
}
private String convertStatus(String status) {
switch (status) {
case "registered":
return "Registrado";
case "processing_payment":
return "Procesando pago";
case "paid":
return "Pagado";
case "cancelled":
return "Cancelado";
default:
return "";
}
}
}
package com.hcordova.flightagencyapi.reservation.dto;
import com.hcordova.flightagencyapi.reservation.domain.models.Reservation;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ReservationPassengerDTO {
private Long id;
private String airportOrigin;
private String airportDestination;
private String reservationMade;
private String status;
private Double cost;
public ReservationPassengerDTO(Reservation reservation) {
this.id = reservation.getId();
this.airportOrigin = reservation.getLegs().get(0).getFlightSchedule().getAirportOrigin().getName();
this.airportDestination = reservation.getLegs().get(0).getFlightSchedule().getAirportDestination().getName();
this.reservationMade = reservation.getCreatedAt().toString();
this.status = convertStatus(reservation.getStatus().getName());
this.cost = reservation.getPayment().getAmount();
}
private String convertStatus(String status) {
switch (status.toLowerCase()) {
case "registered":
return "Registrado";
case "processing_payment":
return "Procesando pago";
case "paid":
return "Pagado";
case "cancelled":
return "Cancelado";
default:
return "";
}
}
}
package com.hcordova.flightagencyapi.reservation.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ReservationSaveDTO {
private Long flightId;
private Long ticketTypeId;
private Long travelClassId;
private Long passengerId;
private Long agentId;
private String reservationMade;
private Double cost;
}
package com.hcordova.flightagencyapi.reservation.dto;
import com.hcordova.flightagencyapi.reservation.domain.models.TicketType;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class TicketTypeDTO {
private Long id;
private String name;
public TicketTypeDTO(TicketType ticketType) {
this.id = ticketType.getId();
this.name = ticketType.getName();
}
}
package com.hcordova.flightagencyapi.reservation.dto;
import com.hcordova.flightagencyapi.reservation.domain.models.TravelClass;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class TravelClassDTO {
private Long id;
private String name;
public TravelClassDTO(TravelClass travelClass) {
this.id = travelClass.getId();
this.name = travelClass.getName();
}
}
package com.hcordova.flightagencyapi.reservation.services;
import java.time.LocalDate;
import java.util.List;
import org.springframework.stereotype.Service;
import com.hcordova.flightagencyapi.agent.domain.services.AgentService;
import com.hcordova.flightagencyapi.flight.domain.services.FlightScheduleService;
import com.hcordova.flightagencyapi.passenger.domain.services.PassengerService;
import com.hcordova.flightagencyapi.payment.domain.models.PaymentStatus;
import com.hcordova.flightagencyapi.payment.domain.services.PaymentStatusService;
import com.hcordova.flightagencyapi.reservation.domain.models.Payment;
import com.hcordova.flightagencyapi.reservation.domain.models.Reservation;
import com.hcordova.flightagencyapi.reservation.domain.repositories.ReservationsRepository;
import com.hcordova.flightagencyapi.reservation.domain.services.ReservationService;
import com.hcordova.flightagencyapi.reservation.domain.services.ReservationStatusService;
import com.hcordova.flightagencyapi.reservation.domain.services.TicketTypeService;
import com.hcordova.flightagencyapi.reservation.domain.services.TravelClassService;
import com.hcordova.flightagencyapi.reservation.dto.ReservationSaveDTO;
import com.hcordova.flightagencyapi.shared.exceptions.NotFoundException;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class ReservationServiceImpl implements ReservationService {
private final ReservationsRepository reservationsRepository;
private final TicketTypeService ticketTypeService;
private final TravelClassService travelClassService;
private final AgentService agentService;
private final PassengerService passengerService;
private final FlightScheduleService flightScheduleService;
private final ReservationStatusService reservationStatusService;
private final PaymentStatusService paymentStatusService;
@Override
public List<Reservation> getAll() {
return reservationsRepository.findByDeletedAtIsNull();
}
@Override
public Reservation getById(Long id) {
return reservationsRepository.findByIdAndDeletedAtIsNull(id)
.orElseThrow(() -> new NotFoundException(String.format("Reservation with id %d not found", id)));
}
@Override
@Transactional
public Reservation save(ReservationSaveDTO reservationDTO) {
Reservation reservation = new Reservation();
var ticketType = ticketTypeService.getById(reservationDTO.getTicketTypeId());
var travelClass = travelClassService.getById(reservationDTO.getTravelClassId());
var passenger = passengerService.getById(reservationDTO.getPassengerId());
var agent = agentService.getById(reservationDTO.getAgentId());
var legs = flightScheduleService.getById(reservationDTO.getFlightId()).getLegs();
var status = reservationStatusService.findByName("registered");
legs.stream().map(leg -> leg.getReservations().add(reservation));
reservation.getLegs().addAll(legs);
try {
reservation.setCreatedAt(LocalDate.parse(reservationDTO.getReservationMade()));
} catch (Exception e) {
throw new RuntimeException("Invalid date format");
}
Payment payment = new Payment();
PaymentStatus paymentStatus = paymentStatusService.findByName("pending");
payment.setDate(LocalDate.now());
payment.setStatus(paymentStatus);
payment.setAmount(reservationDTO.getCost());
reservation.setAgent(agent);
reservation.setPassenger(passenger);
reservation.setTicketType(ticketType);
reservation.setTravelClass(travelClass);
reservation.setStatus(status);
reservation.setPayment(payment);
return reservationsRepository.save(reservation);
}
@Override
public List<Reservation> getByPassengerId(Long id) {
return reservationsRepository.findByDeletedAtIsNullAndPassenger_Id(id);
}
@Override
public Reservation payReservation(Long id) {
Reservation reservation = getById(id);
PaymentStatus paymentStatus = paymentStatusService.findByName("paid");
reservation.getPayment().setStatus(paymentStatus);
reservation.setStatus(reservationStatusService.findByName("paid"));
return reservationsRepository.save(reservation);
}
@Override
public Reservation cancelReservation(Long id) {
Reservation reservation = getById(id);
System.out.println(reservation.getStatus().getName().toLowerCase());
if (reservation.getStatus().getName().toLowerCase().equals("registered")) {
PaymentStatus paymentStatus = paymentStatusService.findByName("refunded");
reservation.getPayment().setStatus(paymentStatus);
reservation.setStatus(reservationStatusService.findByName("Cancelled"));
return reservationsRepository.save(reservation);
} else {
System.out.println(id);
throw new RuntimeException("Reservation already paid");
}
}
@Override
public Reservation deleteReservation(Long id) {
Reservation reservation = getById(id);
if (reservation.getStatus().getName().toLowerCase().equals("registered") ||
reservation.getStatus().getName().toLowerCase().equals("cancelled")) {
reservation.setDeletedAt(LocalDate.now());
return reservationsRepository.save(reservation);
} else {
throw new RuntimeException("Reservation already paid");
}
}
}
package com.hcordova.flightagencyapi.reservation.services;
import java.util.List;
import org.springframework.stereotype.Service;
import com.hcordova.flightagencyapi.reservation.domain.models.TicketType;
import com.hcordova.flightagencyapi.reservation.domain.repositories.TicketTypeRepository;
import com.hcordova.flightagencyapi.reservation.domain.services.TicketTypeService;
import com.hcordova.flightagencyapi.shared.exceptions.NotFoundException;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class TicketTypeServiceImpl implements TicketTypeService {
private final TicketTypeRepository ticketTypeRepository;
@Override
public List<TicketType> getAll() {
return ticketTypeRepository.findAll();
}
@Override
public TicketType getById(Long id) {
return ticketTypeRepository.findById(id)
.orElseThrow(() -> new NotFoundException(String.format("TicketType with id %d not found", id)));
}
}
package com.hcordova.flightagencyapi.reservation.services;
import java.util.List;
import org.springframework.stereotype.Service;
import com.hcordova.flightagencyapi.reservation.domain.models.TravelClass;
import com.hcordova.flightagencyapi.reservation.domain.repositories.TravelClassRepository;
import com.hcordova.flightagencyapi.reservation.domain.services.TravelClassService;
import com.hcordova.flightagencyapi.shared.exceptions.NotFoundException;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class TravelClassServiceImpl implements TravelClassService {
private final TravelClassRepository travelClassRepository;
@Override
public List<TravelClass> getAll() {
return travelClassRepository.findAll();
}
@Override
public TravelClass getById(Long id) {
return travelClassRepository.findById(id)
.orElseThrow(() -> new NotFoundException(String.format("TravelClass with id %d not found", id)));
}
}
...@@ -13,7 +13,6 @@ import org.springframework.util.StringUtils; ...@@ -13,7 +13,6 @@ import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import com.hcordova.flightagencyapi.shared.domain.services.JwtService; import com.hcordova.flightagencyapi.shared.domain.services.JwtService;
import com.hcordova.flightagencyapi.shared.domain.services.UserService;
import jakarta.servlet.FilterChain; import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
...@@ -35,9 +34,10 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { ...@@ -35,9 +34,10 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
final String jwt; final String jwt;
final String userEmail; final String userEmail;
System.out.println(request.getHeader("Authorization"));
if (!StringUtils.hasText(authHeader) || !authHeader.startsWith("Bearer ")) { if (!StringUtils.hasText(authHeader) || !authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response); filterChain.doFilter(request, response);
return; return ;
} }
jwt = authHeader.substring(7); jwt = authHeader.substring(7);
......
package com.hcordova.flightagencyapi.shared.config; package com.hcordova.flightagencyapi.shared.config;
import java.util.Arrays;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
...@@ -15,6 +17,9 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; ...@@ -15,6 +17,9 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
...@@ -25,17 +30,30 @@ public class SecurityConfig { ...@@ -25,17 +30,30 @@ public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthenticationFilter; private final JwtAuthenticationFilter jwtAuthenticationFilter;
private final UserDetailsService userService; private final UserDetailsService userService;
@Bean @Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable) http.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(request -> request.requestMatchers("/api/v1/auth/**") .authorizeHttpRequests(request -> request.requestMatchers("/api/v1/auth/**")
.permitAll().anyRequest().authenticated()) .permitAll().anyRequest().authenticated())
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.sessionManagement(manager -> manager.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .sessionManagement(manager -> manager.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authenticationProvider(authenticationProvider()).addFilterBefore( .authenticationProvider(authenticationProvider()).addFilterBefore(
jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build(); return http.build();
} }
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("*", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
configuration.applyPermitDefaultValues();
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean @Bean
public PasswordEncoder passwordEncoder() { public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); return new BCryptPasswordEncoder();
......
...@@ -2,7 +2,6 @@ package com.hcordova.flightagencyapi.shared.services; ...@@ -2,7 +2,6 @@ package com.hcordova.flightagencyapi.shared.services;
import java.time.LocalDate; import java.time.LocalDate;
import org.springframework.cglib.core.Local;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
......
-- INSERT INTO roles (name) VALUES ('supervisor'), ('agent'), ('passenger'); INSERT INTO roles (name) VALUES ('supervisor'), ('agent'), ('passenger');
-- INSERT INTO airports (name, location, code) INSERT INTO airports (name, location, code)
-- VALUES VALUES
-- ('Jorge Chavez International Airport', 'Lima, Peru', 'LIM'), ('Jorge Chavez International Airport', 'Lima, Peru', 'LIM'),
-- ('John F. Kennedy International Airport', 'New York, USA', 'JFK'), ('John F. Kennedy International Airport', 'New York, USA', 'JFK'),
-- ('Heathrow Airport', 'London, UK', 'LHR'), ('Heathrow Airport', 'London, UK', 'LHR'),
-- ('Charles de Gaulle Airport', 'Paris, France', 'CDG'), ('Charles de Gaulle Airport', 'Paris, France', 'CDG'),
-- ('Los Angeles International Airport', 'Los Angeles, USA', 'LAX'), ('Los Angeles International Airport', 'Los Angeles, USA', 'LAX'),
-- ('Sydney Kingsford Smith Airport', 'Sydney, Australia', 'SYD'), ('Sydney Kingsford Smith Airport', 'Sydney, Australia', 'SYD'),
-- ('Dubai International Airport', 'Dubai, UAE', 'DXB'), ('Dubai International Airport', 'Dubai, UAE', 'DXB'),
-- ('Beijing Capital International Airport', 'Beijing, China', 'PEK'), ('Beijing Capital International Airport', 'Beijing, China', 'PEK'),
-- ('Benito Juarez International Airport', 'Mexico City, Mexico', 'MEX'), ('Benito Juarez International Airport', 'Mexico City, Mexico', 'MEX'),
-- ('Frankfurt Airport', 'Frankfurt, Germany', 'FRA'), ('Frankfurt Airport', 'Frankfurt, Germany', 'FRA'),
-- ('Toronto Pearson International Airport', 'Toronto, Canada', 'YYZ'), ('Toronto Pearson International Airport', 'Toronto, Canada', 'YYZ'),
-- ('Incheon International Airport', 'Seoul, South Korea', 'ICN'), ('Incheon International Airport', 'Seoul, South Korea', 'ICN'),
-- ('Sao Paulo-Guarulhos International Airport', 'Sao Paulo, Brazil', 'GRU'), ('Sao Paulo-Guarulhos International Airport', 'Sao Paulo, Brazil', 'GRU'),
-- ('Barcelona-El Prat Airport', 'Barcelona, Spain', 'BCN'), ('Barcelona-El Prat Airport', 'Barcelona, Spain', 'BCN'),
-- ('Cairo International Airport', 'Cairo, Egypt', 'CAI'); ('Cairo International Airport', 'Cairo, Egypt', 'CAI');
\ No newline at end of file
INSERT INTO airlines (name, code) VALUES
('American Airlines', 'AA'),
('Delta Air Lines', 'DL'),
('United Airlines', 'UA'),
('Emirates', 'EK'),
('Lufthansa', 'LH'),
('British Airways', 'BA'),
('Qatar Airways', 'QR'),
('Air France', 'AF'),
('LATAM Airlines', 'LA');
INSERT INTO aircrafts (name, manufacturer, model) VALUES
('Boeing 737', 'Boeing', '737-800'),
('Airbus A320', 'Airbus', 'A320-200'),
('Boeing 787 Dreamliner', 'Boeing', '787-9'),
('Embraer E175', 'Embraer', 'E175');
-- Insertar fechas y días de la semana para noviembre
INSERT INTO ref_calendar (day_date, day_number) VALUES
('2023-11-01', 3),
('2023-11-02', 4),
('2023-11-03', 5),
('2023-11-04', 6),
('2023-11-05', 7),
('2023-11-06', 1),
('2023-11-07', 2),
('2023-11-08', 3),
('2023-11-09', 4),
('2023-11-10', 5),
('2023-11-11', 6),
('2023-11-12', 7),
('2023-11-13', 1),
('2023-11-14', 2),
('2023-11-15', 3),
('2023-11-16', 4),
('2023-11-17', 5),
('2023-11-18', 6),
('2023-11-19', 7),
('2023-11-20', 1),
('2023-11-21', 2),
('2023-11-22', 3),
('2023-11-23', 4),
('2023-11-24', 5),
('2023-11-25', 6),
('2023-11-26', 7),
('2023-11-27', 1),
('2023-11-28', 2),
('2023-11-29', 3),
('2023-11-30', 4);
-- Insertar fechas y días de la semana para diciembre
INSERT INTO ref_calendar (day_date, day_number) VALUES
('2023-12-01', 5),
('2023-12-02', 6),
('2023-12-03', 7),
('2023-12-04', 1),
('2023-12-05', 2),
('2023-12-06', 3),
('2023-12-07', 4),
('2023-12-08', 5),
('2023-12-09', 6),
('2023-12-10', 7),
('2023-12-11', 1),
('2023-12-12', 2),
('2023-12-13', 3),
('2023-12-14', 4),
('2023-12-15', 5),
('2023-12-16', 6),
('2023-12-17', 7),
('2023-12-18', 1),
('2023-12-19', 2),
('2023-12-20', 3),
('2023-12-21', 4),
('2023-12-22', 5),
('2023-12-23', 6),
('2023-12-24', 7),
('2023-12-25', 1),
('2023-12-26', 2),
('2023-12-27', 3),
('2023-12-28', 4),
('2023-12-29', 5),
('2023-12-30', 6),
('2023-12-31', 7);
INSERT INTO ticket_type (name) VALUES ('Economy'), ('Business'), ('First Class');
INSERT INTO travel_class (name) VALUES ('Economy'), ('Business'), ('First Class');
INSERT INTO reservation_status (name) VALUES ('registered'), ('processing_payment'), ('Cancelled'), ('paid');
INSERT INTO payment_status (name) VALUES ('pending'), ('paid'), ('refunded');
...@@ -64,10 +64,12 @@ ...@@ -64,10 +64,12 @@
"builder": "@angular-devkit/build-angular:dev-server", "builder": "@angular-devkit/build-angular:dev-server",
"configurations": { "configurations": {
"production": { "production": {
"browserTarget": "flight-agency-app:build:production" "browserTarget": "flight-agency-app:build:production",
"proxyConfig": "proxy.conf.json"
}, },
"development": { "development": {
"browserTarget": "flight-agency-app:build:development" "browserTarget": "flight-agency-app:build:development",
"proxyConfig": "proxy.conf.json"
} }
}, },
"defaultConfiguration": "development" "defaultConfiguration": "development"
......
{
"/api": {
"target": "http://localhost:8085",
"secure": false
}
}
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { HomePageComponent } from './pages/home-page/home-page.component';
import { ReservationsComponent } from './pages/reservations/reservations.component'; import { ReservationsComponent } from './pages/reservations/reservations.component';
import { PassengerAddComponent } from './pages/passenger-add/passenger-add.component'; import { PassengerAddComponent } from './pages/passenger-add/passenger-add.component';
import { ReservationAddComponent } from './pages/reservation-add/reservation-add.component'; import { ReservationAddComponent } from './pages/reservation-add/reservation-add.component';
......
<div class="base__fields"> <div class="base__fields">
<div class="field field-passenger"> <div class="field field-passenger">
<shared-input-selector name="Pasajeros" [value]="getPassengerName(getControl('passenger').value)" [tableModel]="passengerModel" [tableData]="passengers" (onSelect)="onSelectedPassenger($event)"></shared-input-selector> <shared-input-selector
name="Pasajeros"
[tableModel]="passengerModel"
[tableData]="passengers"
[control]="getControl('passenger')"
fieldShow="fullname">
</shared-input-selector>
</div> </div>
<div class="field"> <div class="field">
<shared-input-dropdown name="Tipo de ticket" class="field-select" [control]="getControl('ticketType')" [data]="ticketTypes"></shared-input-dropdown> <shared-input-dropdown
name="Tipo de ticket"
class="field-select"
[control]="getControl('ticketType')"
[data]="ticketTypes">
</shared-input-dropdown>
</div> </div>
<div class="field"> <div class="field">
<shared-input-dropdown name="Tipo de pago" class="field-select" [control]="getControl('flightClass')" [data]="flightClass"></shared-input-dropdown> <shared-input-dropdown
name="Tipo de pago"
class="field-select"
[control]="getControl('flightClass')"
[data]="flightClass">
</shared-input-dropdown>
</div> </div>
</div> </div>
...@@ -16,23 +16,17 @@ import { FormControl, FormGroup } from '@angular/forms'; ...@@ -16,23 +16,17 @@ import { FormControl, FormGroup } from '@angular/forms';
}) })
export class BaseInformationComponent { export class BaseInformationComponent {
constructor() {}
public passengerModel: TableModel[] = [ public passengerModel: TableModel[] = [
{ {
name: 'id', name: 'id',
title: '#' title: '#'
}, },
{ {
name: 'name', name: 'fullname',
title: 'Nombre' title: 'Nombre'
}, },
{
name: 'secondName',
title: 'Segundo Nombre'
},
{
name: 'lastname',
title: 'Apellido'
},
{ {
name: 'email', name: 'email',
title: 'Correo' title: 'Correo'
...@@ -45,18 +39,13 @@ export class BaseInformationComponent { ...@@ -45,18 +39,13 @@ export class BaseInformationComponent {
@Input() @Input()
public group: FormGroup = new FormGroup({ public group: FormGroup = new FormGroup({
passenger: new FormControl<string | null>(null), passenger: new FormControl<number | null>(null),
ticketType: new FormControl<string | null>(null), ticketType: new FormControl<number | null>(null),
flightClass: new FormControl<string | null>(null), flightClass: new FormControl<number | null>(null),
}); });
constructor() { } getControl(name: string): FormControl<number | null> {
return this.group.get(name) as FormControl<number | null>;
getControl(name: string): FormControl<string | null> {
return this.group.get(name) as FormControl<string | null>;
}
ngOnInit(): void {
} }
@Input() @Input()
...@@ -67,15 +56,4 @@ export class BaseInformationComponent { ...@@ -67,15 +56,4 @@ export class BaseInformationComponent {
@Input() @Input()
public flightClass: DropdownElement[] = []; public flightClass: DropdownElement[] = [];
onSelectedPassenger(passenger: Passenger): void {
this.group.get('passenger')?.setValue(passenger.id);
}
getPassengerName(id: string | null): string | null {
if (id) {
const passenger = this.passengers.find(passenger => passenger.id === Number.parseInt(id));
return passenger ? `${passenger.name} ${passenger.lastname}` : null;
} return null;
}
} }
...@@ -6,8 +6,7 @@ ...@@ -6,8 +6,7 @@
name="Aeropuerto origen" name="Aeropuerto origen"
[tableModel]="airportModel" [tableModel]="airportModel"
[tableData]="airports" [tableData]="airports"
(onSelect)="onSelectAirportOrigin($event)" [control]="airportOriginControl">
[value]="getControl('airportOrigin').value">
</shared-input-selector> </shared-input-selector>
</div> </div>
<div class="field field-airport-destination"> <div class="field field-airport-destination">
...@@ -15,16 +14,18 @@ ...@@ -15,16 +14,18 @@
name="Aeropuerto destino" name="Aeropuerto destino"
[tableModel]="airportModel" [tableModel]="airportModel"
[tableData]="airports" [tableData]="airports"
(onSelect)="onSelectAirportDestination($event)" [control]="airportDestinationControl">
[value]="getControl('airportDestination').value">
</shared-input-selector> </shared-input-selector>
</div> </div>
<div class="field field-date-start"> <div class="field field-date-start">
<shared-input-calendar name="Fecha" [control]="getControl('date')"></shared-input-calendar> <shared-input-calendar
[control]="dateControl"
name="Fecha">
</shared-input-calendar>
</div> </div>
</div> </div>
<div class="search__actions"> <div class="search__actions">
<button (click)="onSearchFlights()" class="btn btn-filtrar">Filtrar</button> <button [disabled]="group.invalid" (click)="onSearchFlights()" class="btn btn-filtrar">Filtrar</button>
</div> </div>
</form> </form>
<shared-table-search [tableModel]="flightModel" [tableData]="flightResults" (onSelect)="onEventSelectFlight($event)"></shared-table-search> <shared-table-search [tableModel]="flightModel" [tableData]="flightResults" (onSelect)="onEventSelectFlight($event)"></shared-table-search>
......
...@@ -3,7 +3,7 @@ import { TableModel } from 'src/app/shared/interfaces/table-model.interface'; ...@@ -3,7 +3,7 @@ import { TableModel } from 'src/app/shared/interfaces/table-model.interface';
import { AirportsService } from '../../services/airports.service'; import { AirportsService } from '../../services/airports.service';
import { Airport } from '../../interfaces/airport.interface'; import { Airport } from '../../interfaces/airport.interface';
import { FlightService } from 'src/app/supervisor/services/flight.service'; import { FlightService } from 'src/app/supervisor/services/flight.service';
import { FormControl, FormGroup } from '@angular/forms'; import { FormControl, FormGroup, Validators } from '@angular/forms';
import { Flight } from 'src/app/supervisor/interfaces/flight.interface'; import { Flight } from 'src/app/supervisor/interfaces/flight.interface';
@Component({ @Component({
...@@ -39,17 +39,29 @@ export class FlightInformationComponent implements OnInit { ...@@ -39,17 +39,29 @@ export class FlightInformationComponent implements OnInit {
@Input() @Input()
public group: FormGroup = new FormGroup({ public group: FormGroup = new FormGroup({
airportOrigin: new FormControl<string | null>(null), airportOrigin: new FormControl<number | null>(null),
airportDestination: new FormControl<string | null>(null), airportDestination: new FormControl<number | null>(null),
date: new FormControl<string | null>(null) date: new FormControl<string | null>(null)
}); });
getControl(name: string): FormControl<string | null> { get airportOriginControl(): FormControl<number | null> {
return this.group.get(name) as FormControl<string | null>; return this.group.get('airportOrigin') as FormControl<number | null>;
} }
public airports: Airport[] = []; get airportDestinationControl(): FormControl<number | null> {
return this.group.get('airportDestination') as FormControl<number | null>;
}
get dateControl(): FormControl<string | null> {
return this.group.get('date') as FormControl<string | null>;
}
get airportOriginName(): string {
const airport = this.airports.find(airport => airport.id === this.airportOriginControl.value);
return airport?.name || '';
}
public airports: Airport[] = [];
constructor( constructor(
private airpotsService: AirportsService, private airpotsService: AirportsService,
...@@ -59,25 +71,23 @@ export class FlightInformationComponent implements OnInit { ...@@ -59,25 +71,23 @@ export class FlightInformationComponent implements OnInit {
this.airpotsService.getAll() this.airpotsService.getAll()
.subscribe(airports => this.airports = airports); .subscribe(airports => this.airports = airports);
this.flightSelected ? this.flightResults.push(this.flightSelected) : []; if (this.group.value.airportOrigin !== null && this.group.value.airportDestination !== null && this.group.value.date !== null) {
}
onSelectAirportOrigin(airport: Airport): void {
this.getControl('airportOrigin').setValue(airport.name);
}
onSelectAirportDestination(airport: Airport): void {
this.getControl('airportDestination').setValue(airport.name);
}
onSearchFlights(): void {
this.group.markAllAsTouched();
if (this.group.valid) {
this.flightService.searchFlight(this.group.value.airportOrigin, this.group.value.airportDestination, this.group.value.date) this.flightService.searchFlight(this.group.value.airportOrigin, this.group.value.airportDestination, this.group.value.date)
.subscribe(flights => { .subscribe(flights => {
this.flightResults = flights; this.flightResults = flights;
}); });
} }
this.flightSelected ? this.flightResults.push(this.flightSelected) : [];
}
onSearchFlights(): void {
const formValues = this.group.value;
this.flightService.searchFlight(formValues.airportOrigin, formValues.airportDestination, formValues.date)
.subscribe(flights => {
console.log(flights);
this.flightResults = flights;
});
} }
@Output() @Output()
......
...@@ -41,11 +41,11 @@ ...@@ -41,11 +41,11 @@
</div> </div>
<div class="flight__content-item"> <div class="flight__content-item">
<span class="content__item-label">Fecha de partida</span> <span class="content__item-label">Fecha de partida</span>
<span class="content__item_value">{{ flightSelected?.dateStart }}</span> <span class="content__item_value">{{ flightSelected?.departureDate }}</span>
</div> </div>
<div class="flight__content-item"> <div class="flight__content-item">
<span class="content__item-label">Fecha de llegada</span> <span class="content__item-label">Fecha de llegada</span>
<span class="content__item_value">{{ flightSelected?.dateEnd }}</span> <span class="content__item_value">{{ flightSelected?.arrivalDate }}</span>
</div> </div>
<div class="flight__content-item"> <div class="flight__content-item">
<span class="content__item-label">Aerolinea</span> <span class="content__item-label">Aerolinea</span>
...@@ -53,11 +53,11 @@ ...@@ -53,11 +53,11 @@
</div> </div>
<div class="flight__content-item"> <div class="flight__content-item">
<span class="content__item-label">Tipo de vuelo</span> <span class="content__item-label">Tipo de vuelo</span>
<span class="content__item_value">{{ flighType }}</span> <span class="content__item_value">{{ flightSelected?.flightType }}</span>
</div> </div>
<div class="flight__content-item"> <div class="flight__content-item">
<span class="content__item-label">Precio</span> <span class="content__item-label">Precio</span>
<span class="content__item_value">{{ totalCost }} USD</span> <span class="content__item_value">{{ flightSelected?.price }} USD</span>
</div> </div>
</div> </div>
</section> </section>
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
<h3 class="detail__header-title">Detalle de vuelo</h3> <h3 class="detail__header-title">Detalle de vuelo</h3>
</div> </div>
<div class="detail__content"> <div class="detail__content">
<shared-table-search [tableModel]="scaleModel" [tableData]="flightSelected?.scales || []"></shared-table-search> <shared-table-search [tableModel]="scaleModel" [tableData]="flightSelected?.legs || []"></shared-table-search>
</div> </div>
</section> </section>
</div> </div>
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, Input, Output } from '@angular/core';
import { TableModel } from 'src/app/shared/interfaces/table-model.interface'; import { TableModel } from 'src/app/shared/interfaces/table-model.interface';
import { CostFlight } from 'src/app/supervisor/interfaces/cost-flight.interface'; import { FlightCost } from 'src/app/supervisor/interfaces/flight-cost.interface';
import { Flight } from 'src/app/supervisor/interfaces/flight.interface'; import { Flight } from 'src/app/supervisor/interfaces/flight.interface';
@Component({ @Component({
...@@ -24,11 +24,11 @@ export class SummaryInformationComponent { ...@@ -24,11 +24,11 @@ export class SummaryInformationComponent {
title: 'Destino' title: 'Destino'
}, },
{ {
name: 'dateStart', name: 'departureDateTime',
title: 'Fecha de salida' title: 'Fecha de salida'
}, },
{ {
name: 'dateEnd', name: 'arrivalDateTime',
title: 'Fecha de llegada' title: 'Fecha de llegada'
} }
] ]
...@@ -49,14 +49,10 @@ export class SummaryInformationComponent { ...@@ -49,14 +49,10 @@ export class SummaryInformationComponent {
public onChangeStep: EventEmitter<number> = new EventEmitter<number>(); public onChangeStep: EventEmitter<number> = new EventEmitter<number>();
get flighType(): string {
return this.flightSelected ? this.flightSelected.scales.length > 1 ? 'Con escalas' : 'Directo' : '';
}
get totalCost(): number | null { get totalCost(): number | null {
const costs = this.flightSelected?.costs; const costs = this.flightSelected?.costs;
const date: Date = new Date(this.flightSelected?.dateStart as string); const date: Date = new Date(this.flightSelected?.departureDate as string);
const cost: CostFlight | null = null; const cost: FlightCost | null = null;
if (costs) { if (costs) {
for (let i = 0; i < costs.length; i++) { for (let i = 0; i < costs.length; i++) {
......
export interface PassengerSave {
name: string;
lastname: string;
phone: string;
country: string;
city: string;
address: string;
email: string;
password: string;
role: string
}
export interface Passenger { export interface Passenger {
id: number; id: number;
name: string; name: string;
secondName: string; fullname?: string;
lastname: string; lastname: string;
phone: string; phone: string;
country: string; country: string;
city: string; city: string;
address: string; address: string;
email: string; email: string;
password: string; password?: string;
role?: string;
} }
export const EMPTY_PASSENGER: Passenger = { export const EMPTY_PASSENGER: Passenger = {
id: 0, id: 0,
name: '', name: '',
secondName: '',
lastname: '', lastname: '',
country: '', country: '',
city: '', city: '',
address: '', address: '',
phone: '', phone: '',
email: '', email: '',
password: ''
}; };
export interface ReservationSave {
flightId: number;
agentId: number;
passengerId: number;
ticketTypeId: number;
travelClassId: number;
reservationMade: string;
cost: number;
}
interface Reservation { export interface Reservation {
id?: number; id?: number;
agentId: number; agentId: number;
passenger?: string;
passengerId: number; passengerId: number;
passengerName: string; ticketTypeId: number;
statusCode: ReservationStatusCode; travelClassId: number;
ticketTypeCode: number; status: string;
ticketTypeName: string; airportOriginId: number;
travelClassCode: number; airporOrigin?: string;
travelClassName: string; airportDestinationId: number;
dateReservationMade: string; airportDestination?: string;
reservationMade: string;
departureDate: string;
flightId: number; flightId: number;
} }
type ReservationStatusCode = 'REGISTRADO' | 'PROCESANDO_PAGO' | 'CANCELADO' | 'PAGADO';
export { Reservation, ReservationStatusCode };
...@@ -31,11 +31,7 @@ ...@@ -31,11 +31,7 @@
gap: 16px; gap: 16px;
} }
.field-address { .field-name, .field-address, .field-email, .field-password {
grid-column: 1 / 3;
}
.field-email, .field-password {
grid-column: 1 / 3; grid-column: 1 / 3;
} }
......
...@@ -14,11 +14,6 @@ ...@@ -14,11 +14,6 @@
<label for="field-name">Nombre *</label> <label for="field-name">Nombre *</label>
<shared-input-validator [formGroup]="passengerForm" field="name" [getValidatorLength]="getPassengerValidatorLenght"></shared-input-validator> <shared-input-validator [formGroup]="passengerForm" field="name" [getValidatorLength]="getPassengerValidatorLenght"></shared-input-validator>
</div> </div>
<div class="field field-second">
<input type="text" name="secondName" formControlName="secondName" id="field-second">
<label for="field-second">Segundo nombre *</label>
<shared-input-validator [formGroup]="passengerForm" field="secondName" [getValidatorLength]="getPassengerValidatorLenght"></shared-input-validator>
</div>
<div class="field field-lastname"> <div class="field field-lastname">
<input type="text" name="lastname" formControlName="lastname" id="field-lastname"> <input type="text" name="lastname" formControlName="lastname" id="field-lastname">
<label for="field-lastname">Apellidos *</label> <label for="field-lastname">Apellidos *</label>
......
...@@ -5,6 +5,7 @@ import { PassengerService } from '../../services/passenger.service'; ...@@ -5,6 +5,7 @@ import { PassengerService } from '../../services/passenger.service';
import { EMPTY_PASSENGER, Passenger } from '../../interfaces/passenger.interface'; import { EMPTY_PASSENGER, Passenger } from '../../interfaces/passenger.interface';
import { PASSENGER_VALIDATORS, getPassengerValidatorLenght } from '../../validators/passenger.validator'; import { PASSENGER_VALIDATORS, getPassengerValidatorLenght } from '../../validators/passenger.validator';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { SecurityService } from 'src/app/security/services/security.service';
@Component({ @Component({
selector: 'app-passenger-add', selector: 'app-passenger-add',
...@@ -19,6 +20,7 @@ export class PassengerAddComponent implements OnInit { ...@@ -19,6 +20,7 @@ export class PassengerAddComponent implements OnInit {
constructor( constructor(
private location: Location, private location: Location,
private activatedRoute: ActivatedRoute, private activatedRoute: ActivatedRoute,
private securityService: SecurityService,
private passengerService: PassengerService) { } private passengerService: PassengerService) { }
ngOnInit(): void { ngOnInit(): void {
...@@ -35,7 +37,6 @@ export class PassengerAddComponent implements OnInit { ...@@ -35,7 +37,6 @@ export class PassengerAddComponent implements OnInit {
buildForm(passenger: Passenger): void { buildForm(passenger: Passenger): void {
this.passengerForm.get('name')?.setValue(passenger.name || ''); this.passengerForm.get('name')?.setValue(passenger.name || '');
this.passengerForm.get('secondName')?.setValue(passenger.secondName || '');
this.passengerForm.get('lastname')?.setValue(passenger.lastname || ''); this.passengerForm.get('lastname')?.setValue(passenger.lastname || '');
this.passengerForm.get('country')?.setValue(passenger.country || ''); this.passengerForm.get('country')?.setValue(passenger.country || '');
this.passengerForm.get('city')?.setValue(passenger.city || ''); this.passengerForm.get('city')?.setValue(passenger.city || '');
...@@ -58,7 +59,7 @@ export class PassengerAddComponent implements OnInit { ...@@ -58,7 +59,7 @@ export class PassengerAddComponent implements OnInit {
this.location.back(); this.location.back();
}); });
} else { } else {
this.passengerService.save(this.passengerForm.value) this.securityService.signup({...this.passengerForm.value, role: 'passenger'})
.subscribe(() => { .subscribe(() => {
this.passengerForm.reset(); this.passengerForm.reset();
this.location.back(); this.location.back();
......
...@@ -17,8 +17,9 @@ ...@@ -17,8 +17,9 @@
<div *ngSwitchCase="1"> <div *ngSwitchCase="1">
<agent-flight-information <agent-flight-information
(onSelectFlight)="onSelectFlight($event)" (onSelectFlight)="onSelectFlight($event)"
[group]="formFlightInformation" [flightSelected]="flightSelected" [flightSelected]="flightSelected"
[flightModel]="flightModel"> [flightModel]="flightModel"
[group]="formFlightInformation">
</agent-flight-information> </agent-flight-information>
</div> </div>
<div *ngSwitchCase="2"> <div *ngSwitchCase="2">
......
...@@ -8,11 +8,13 @@ import { Flight } from 'src/app/supervisor/interfaces/flight.interface'; ...@@ -8,11 +8,13 @@ import { Flight } from 'src/app/supervisor/interfaces/flight.interface';
import { TicketTypeService } from '../../services/ticket-type.service'; import { TicketTypeService } from '../../services/ticket-type.service';
import { TicketClassService } from '../../services/ticket-class.service'; import { TicketClassService } from '../../services/ticket-class.service';
import { DropdownElement } from 'src/app/shared/interfaces/dropdown-element-interface'; import { DropdownElement } from 'src/app/shared/interfaces/dropdown-element-interface';
import { Reservation, ReservationStatusCode } from '../../interfaces/reservation.interface'; import { Reservation } from '../../interfaces/reservation.interface';
import { ReservationsService } from '../../services/reservations.service'; import { ReservationsService } from '../../services/reservations.service';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { FlightService } from 'src/app/supervisor/services/flight.service'; import { FlightService } from 'src/app/supervisor/services/flight.service';
import { SecurityService } from 'src/app/security/services/security.service';
import { ReservationSave } from '../../interfaces/reservation-save.interface';
@Component({ @Component({
selector: 'app-reservation-add', selector: 'app-reservation-add',
...@@ -52,7 +54,7 @@ export class ReservationAddComponent implements OnInit{ ...@@ -52,7 +54,7 @@ export class ReservationAddComponent implements OnInit{
title: 'Aerolinea' title: 'Aerolinea'
}, },
{ {
name: 'aircraftType', name: 'aircraft',
title: 'Tipo de avión' title: 'Tipo de avión'
}, },
{ {
...@@ -60,11 +62,11 @@ export class ReservationAddComponent implements OnInit{ ...@@ -60,11 +62,11 @@ export class ReservationAddComponent implements OnInit{
title: 'Tipo de vuelo' title: 'Tipo de vuelo'
}, },
{ {
name: 'dateStart', name: 'departureDate',
title: 'Hora de inicio' title: 'Hora de inicio'
}, },
{ {
name: 'dateEnd', name: 'arrivalDate',
title: 'Hora de llegada' title: 'Hora de llegada'
}, },
{ {
...@@ -82,33 +84,39 @@ export class ReservationAddComponent implements OnInit{ ...@@ -82,33 +84,39 @@ export class ReservationAddComponent implements OnInit{
}); });
public formFlightInformation: FormGroup = new FormGroup({ public formFlightInformation: FormGroup = new FormGroup({
airportOrigin: new FormControl<string | null>(null, [Validators.required]), airportOrigin: new FormControl<number | null>(null, [Validators.required]),
airportDestination: new FormControl<string | null>(null, [Validators.required]), airportDestination: new FormControl<number | null>(null, [Validators.required]),
date: new FormControl<string | null>(null, [Validators.required]) date: new FormControl<string | null>(null, [Validators.required])
}); });
public passengers: Passenger[] = [];
public ticketTypes: DropdownElement[] = [];
public flightClass: DropdownElement[] = [];
get passengerName(): string { get passengerName(): string {
const passengerId = this.formBaseInformation.get('passenger')?.value; if (this.formBaseInformation.value) {
const passenger = this.passengers.find(passenger => passenger.id === passengerId); const passenger = this.passengers.find(passenger => passenger.id == this.formBaseInformation.value.passenger);
return passenger ? passenger.name + ' ' + passenger.lastname: ''; return passenger ? `${passenger?.name} ${passenger?.lastname}` : "";
}
return "";
} }
get ticketTypeName(): string { get ticketTypeName(): string {
const ticketTypeId = this.formBaseInformation.get('ticketType')?.value; if (this.formBaseInformation.value) {
const ticketType = this.ticketTypes.find(ticketType => ticketType.value === ticketTypeId); const ticketType = this.ticketTypes.find(ticketType => ticketType.value == this.formBaseInformation.value.ticketType);
return ticketType ? ticketType.text : ''; return ticketType ? ticketType.text : "";
}
return "";
} }
get flightClassName(): string { get flightClassName(): string {
const flightClassId = this.formBaseInformation.get('flightClass')?.value; if (this.formBaseInformation.value) {
const flightClass = this.flightClass.find(flightClass => flightClass.value === flightClassId); const flightClass = this.flightClass.find(flightClass => flightClass.value == this.formBaseInformation.value.flightClass);
return flightClass ? flightClass.text : ''; return flightClass ? flightClass.text : "";
}
return "";
} }
public passengers: Passenger[] = [];
public ticketTypes: DropdownElement[] = [];
public flightClass: DropdownElement[] = [];
get isInvalidThisStep(): boolean { get isInvalidThisStep(): boolean {
if (this.stepIndex == 0) return this.formBaseInformation.invalid; if (this.stepIndex == 0) return this.formBaseInformation.invalid;
if (this.stepIndex == 1) return this.formFlightInformation.invalid || this.flightSelected === null; if (this.stepIndex == 1) return this.formFlightInformation.invalid || this.flightSelected === null;
...@@ -121,7 +129,8 @@ export class ReservationAddComponent implements OnInit{ ...@@ -121,7 +129,8 @@ export class ReservationAddComponent implements OnInit{
private reservationsService: ReservationsService, private reservationsService: ReservationsService,
private flightService: FlightService, private flightService: FlightService,
private location: Location, private location: Location,
private activatedRoute: ActivatedRoute) { } private activatedRoute: ActivatedRoute,
private securityService: SecurityService) { }
ngOnInit(): void { ngOnInit(): void {
this.activatedRoute.params this.activatedRoute.params
...@@ -130,14 +139,15 @@ export class ReservationAddComponent implements OnInit{ ...@@ -130,14 +139,15 @@ export class ReservationAddComponent implements OnInit{
this.reservationsService.getById(params['id']) this.reservationsService.getById(params['id'])
.subscribe(reservation => { .subscribe(reservation => {
this.formBaseInformation.get('passenger')?.setValue(reservation.passengerId); this.formBaseInformation.get('passenger')?.setValue(reservation.passengerId);
this.formBaseInformation.get('ticketType')?.setValue(reservation.travelClassCode.toString()); this.formBaseInformation.get('ticketType')?.setValue(reservation.ticketTypeId);
this.formBaseInformation.get('flightClass')?.setValue(reservation.ticketTypeCode.toString()); this.formBaseInformation.get('flightClass')?.setValue(reservation.travelClassId);
this.flightService.getById(reservation.flightId) this.formFlightInformation.get('airportOrigin')?.setValue(reservation.airportOriginId);
.subscribe(flight => { this.formFlightInformation.get('airportDestination')?.setValue(reservation.airportDestinationId);
this.flightSelected = flight; this.formFlightInformation.get('date')?.setValue(reservation.departureDate);
this.formFlightInformation.get('airportOrigin')?.setValue(flight.airportOrigin); this.flightService.searchFlight(reservation.airportOriginId, reservation.airportDestinationId, reservation.departureDate)
this.formFlightInformation.get('airportDestination')?.setValue(flight.airportDestination); .subscribe(flights => {
this.formFlightInformation.get('date')?.setValue(flight.dateStart); // this.flightResults = flights;
this.flightSelected = flights.find(flight => flight.id === reservation.flightId) || null;
}) })
}) })
} }
...@@ -152,14 +162,14 @@ export class ReservationAddComponent implements OnInit{ ...@@ -152,14 +162,14 @@ export class ReservationAddComponent implements OnInit{
this.ticketTypesService.getAll() this.ticketTypesService.getAll()
.subscribe(ticketTypes => { .subscribe(ticketTypes => {
ticketTypes.map(ticketType => { ticketTypes.map(ticketType => {
this.ticketTypes.push({ text: ticketType.name, value: ticketType.id.toString() }); this.ticketTypes.push({ text: ticketType.name, value: ticketType.id});
}); });
}); });
this.ticketClassService.getAll() this.ticketClassService.getAll()
.subscribe(flightClass => { .subscribe(flightClass => {
flightClass.map(flight => { flightClass.map(flight => {
this.flightClass.push({ text: flight.name, value: flight.id.toString() }); this.flightClass.push({ text: flight.name, value: flight.id });
}) })
}); });
} }
...@@ -198,19 +208,18 @@ export class ReservationAddComponent implements OnInit{ ...@@ -198,19 +208,18 @@ export class ReservationAddComponent implements OnInit{
} }
onSaveBooking(): void { onSaveBooking(): void {
const reservation: Reservation = { const reservation: ReservationSave = {
agentId: 1, agentId: this.securityService.currentUser?.id || 0,
passengerId: this.formBaseInformation.value.passenger, passengerId: this.formBaseInformation.value.passenger,
passengerName: this.passengerName, travelClassId: parseInt(this.formBaseInformation.value.ticketType),
travelClassCode: parseInt(this.formBaseInformation.value.ticketType), ticketTypeId: parseInt(this.formBaseInformation.value.flightClass),
travelClassName: this.ticketTypeName, reservationMade: this.formFlightInformation.value.date,
ticketTypeCode: parseInt(this.formBaseInformation.value.flightClass), flightId: this.flightSelected?.id || 0,
ticketTypeName: this.flightClassName, cost: this.flightSelected?.price || 0
statusCode: 'REGISTRADO',
dateReservationMade: new Date().toLocaleDateString(),
flightId: this.flightSelected?.id || 0
}; };
console.log(reservation);
this.reservationsService.save(reservation) this.reservationsService.save(reservation)
.subscribe(() => { .subscribe(() => {
this.formBaseInformation.reset(); this.formBaseInformation.reset();
......
.btn-add {
border: 1px solid #ccc;
color: #676a6c;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
width: 32px;
height: 32px;
box-shadow: 0 5px 5px -3px #0003, 0 8px 10px 1px #00000024, 0 3px 14px 2px #0000001f;
}
...@@ -3,12 +3,25 @@ ...@@ -3,12 +3,25 @@
title="Reservas" title="Reservas"
icon="bi-bookmarks-fill" icon="bi-bookmarks-fill"
message="Este gestor permite realizar reservas de vuelos"> message="Este gestor permite realizar reservas de vuelos">
<shared-table <shared-table-custom
[tableData]="tableData" [tableData]="tableData"
[tableModel]="tableModel" [tableModel]="tableModel"
(onReloadData)="getAll()" [tableAction]="actions">
(onDialogResult)="onDelete($event)" <div class="more-actions">
newRouter="new" <button [routerLink]="'new'" class="btn btn-add">
editRouter="edit"> <span class="bi bi-file-earmark"></span>
</shared-table> </button>
</div>
</shared-table-custom>
<shared-delete-dialog
*ngIf="openDeleteDialog"
(onDialogResult)="onHandlerResult($event)">
</shared-delete-dialog>
<shared-confirm-dialog
title="Cancelar reserva"
message="¿Esta seguro que desea cancelar la reserva?"
icon="bi-bookmark-x-fill"
*ngIf="openCancelDialog"
(onDialogResult)="onHandleCancel($event)">
</shared-confirm-dialog>
</shared-mail-box> </shared-mail-box>
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { TableModel } from 'src/app/shared/interfaces/table-model.interface'; import { TableModel } from 'src/app/shared/interfaces/table-model.interface';
import { BookingService } from '../../services/booking.service';
import { Booking } from '../../interfaces/booking.interface';
import { ResultDelete } from 'src/app/shared/interfaces/result-delete.interface'; import { ResultDelete } from 'src/app/shared/interfaces/result-delete.interface';
import { Reservation } from '../../interfaces/reservation.interface'; import { Reservation } from '../../interfaces/reservation.interface';
import { ReservationsService } from '../../services/reservations.service'; import { ReservationsService } from '../../services/reservations.service';
import { TableAction } from 'src/app/shared/interfaces/table-action.interface';
import { Router } from '@angular/router';
@Component({ @Component({
selector: 'app-reservations', selector: 'app-reservations',
...@@ -15,30 +15,57 @@ export class ReservationsComponent implements OnInit{ ...@@ -15,30 +15,57 @@ export class ReservationsComponent implements OnInit{
tableData: Reservation[] = []; tableData: Reservation[] = [];
openDeleteDialog: boolean = false;
openCancelDialog: boolean = false;
actions: TableAction[] = [
{
title: 'Editar',
icon: 'bi-pencil-square',
disabled: (item) => item.status === 'Pagado',
action: (item) => { this.router.navigate(['/agents/reservations/edit', item.id]); }
},
{
title: 'Eliminar',
icon: 'bi-trash',
disabled: (item) => item.status === 'Pagado',
action: (item) => { this.openDeleteDialog = true; this.reservationSelected = item; }
},
{
title: "Cancelar",
icon: "bi-x-circle",
disabled: (item) => item.status === 'Pagado' || item.status === 'Cancelado',
action: (item) => { this.openCancelDialog = true; this.reservationSelected = item; }
}
]
reservationSelected: Reservation | null = null;
tableModel: TableModel[] = [ tableModel: TableModel[] = [
{ {
name: 'id', name: 'id',
title: '#' title: '#'
}, },
{ {
name: 'passengerName', name: 'passenger',
title: 'Pasajero' title: 'Pasajero'
}, },
{ {
name: 'ticketTypeName', name: 'ticketType',
title: 'Tipo de Ticket' title: 'Tipo de ticket'
}, },
{ {
name: 'travelClassName', name: 'travelClass',
title: 'Clase' title: 'Clase de viaje'
}, },
{ {
name: 'statusCode', name: 'status',
title: 'Estado' title: 'Estado'
} }
]; ];
constructor(private reservationsService: ReservationsService) { } constructor(private reservationsService: ReservationsService,
private router: Router) { }
ngOnInit(): void { ngOnInit(): void {
this.getAll(); this.getAll();
...@@ -54,4 +81,20 @@ export class ReservationsComponent implements OnInit{ ...@@ -54,4 +81,20 @@ export class ReservationsComponent implements OnInit{
this.reservationsService.delete(result.id) this.reservationsService.delete(result.id)
.subscribe(() => this.getAll()); .subscribe(() => this.getAll());
} }
onHandlerResult(result: boolean): void {
if (result) {
this.reservationsService.delete(this.reservationSelected?.id!)
.subscribe(() => this.getAll());
}
this.openDeleteDialog = false;
}
onHandleCancel(result: boolean): void {
if (result) {
this.reservationsService.cancelReservation(this.reservationSelected?.id!)
.subscribe(() => this.getAll());
}
this.openCancelDialog = false;
}
} }
...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core'; ...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { Airport } from '../interfaces/airport.interface'; import { Airport } from '../interfaces/airport.interface';
import { headers } from 'src/app/shared/utils/header.util';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class AirportsService { export class AirportsService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
private BASE_URL: string = 'http://localhost:3000/airports'; private BASE_URL: string = 'http://localhost:8085/api/v1/airports';
getAll(): Observable<Airport[]> { getAll(): Observable<Airport[]> {
return this.http.get<Airport[]>(this.BASE_URL); return this.http.get<Airport[]>(this.BASE_URL, { headers });
} }
} }
...@@ -2,30 +2,31 @@ import { Injectable } from '@angular/core'; ...@@ -2,30 +2,31 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Passenger } from '../interfaces/passenger.interface'; import { Passenger } from '../interfaces/passenger.interface';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { headers } from 'src/app/shared/utils/header.util';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class PassengerService { export class PassengerService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
URL_BASE: string = 'http://localhost:3000/passengers'; URL_BASE: string = 'http://localhost:8085/api/v1/passengers';
getAll(): Observable<Passenger[]> { getAll(): Observable<Passenger[]> {
return this.http.get<Passenger[]>(this.URL_BASE); return this.http.get<Passenger[]>(this.URL_BASE, { headers });
} }
getById(id: number): Observable<Passenger> { getById(id: number): Observable<Passenger> {
return this.http.get<Passenger>(`${this.URL_BASE}/${id}`); return this.http.get<Passenger>(`${this.URL_BASE}/${id}`, { headers });
} }
save(passenger: Passenger): Observable<Passenger> { save(passenger: Passenger): Observable<Passenger> {
return this.http.post<Passenger>(this.URL_BASE, passenger); return this.http.post<Passenger>(this.URL_BASE, passenger, { headers });
} }
edit(id: number, passenger: Passenger): Observable<Passenger> { edit(id: number, passenger: Passenger): Observable<Passenger> {
return this.http.put<Passenger>(`${this.URL_BASE}/${id}`, passenger); return this.http.put<Passenger>(`${this.URL_BASE}/${id}`, passenger, { headers });
} }
delete(id: number): Observable<Passenger> { delete(id: number): Observable<Passenger> {
return this.http.delete<Passenger>(`${this.URL_BASE}/${id}`); return this.http.delete<Passenger>(`${this.URL_BASE}/${id}`, { headers });
} }
} }
...@@ -2,27 +2,38 @@ import { Injectable } from '@angular/core'; ...@@ -2,27 +2,38 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Reservation } from '../interfaces/reservation.interface'; import { Reservation } from '../interfaces/reservation.interface';
import { Observable, tap } from 'rxjs'; import { Observable, tap } from 'rxjs';
import { headers } from 'src/app/shared/utils/header.util';
import { ReservationSave } from '../interfaces/reservation-save.interface';
import { ReservationDetail } from 'src/app/passenger/interfaces/reservation-detail.interface';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class ReservationsService { export class ReservationsService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
URL_BASE: string = 'http://localhost:3000/reservations'; URL_BASE: string = 'http://localhost:8085/api/v1/reservations';
getAll(): Observable<Reservation[]> { getAll(): Observable<Reservation[]> {
return this.http.get<Reservation[]>(this.URL_BASE); return this.http.get<Reservation[]>(this.URL_BASE, { headers});
} }
getById(id: number): Observable<Reservation> { getById(id: number): Observable<Reservation> {
return this.http.get<Reservation>(`${this.URL_BASE}/${id}`); return this.http.get<Reservation>(`${this.URL_BASE}/${id}`, { headers });
} }
getByPassengerId(id: number): Observable<Reservation[]> { getByPassengerId(id: number): Observable<ReservationDetail[]> {
return this.http.get<Reservation[]>(`${this.URL_BASE}?passengerId=${id}`); return this.http.get<ReservationDetail[]>(`${this.URL_BASE}/passenger/${id}`, { headers });
} }
save(reservation: Reservation): Observable<Reservation> { payReservation(id: number): Observable<ReservationDetail> {
return this.http.post<Reservation>(this.URL_BASE, reservation); return this.http.put<ReservationDetail>(`${this.URL_BASE}/pay/${id}`, null, { headers });
}
cancelReservation(id: number): Observable<ReservationDetail> {
return this.http.put<ReservationDetail>(`${this.URL_BASE}/cancel/${id}`, null, { headers });
}
save(reservation: ReservationSave): Observable<Reservation> {
return this.http.post<Reservation>(this.URL_BASE, reservation, { headers });
} }
edit(id: number, reservation: Reservation): Observable<Reservation> { edit(id: number, reservation: Reservation): Observable<Reservation> {
...@@ -30,6 +41,6 @@ export class ReservationsService { ...@@ -30,6 +41,6 @@ export class ReservationsService {
} }
delete(id: number): Observable<Reservation> { delete(id: number): Observable<Reservation> {
return this.http.delete<Reservation>(`${this.URL_BASE}/${id}`); return this.http.delete<Reservation>(`${this.URL_BASE}/${id}`, { headers });
} }
} }
...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core'; ...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { FlightClass } from '../interfaces/flight-class.interface'; import { FlightClass } from '../interfaces/flight-class.interface';
import { headers } from 'src/app/shared/utils/header.util';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class TicketClassService { export class TicketClassService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
private BASE_URL: string = 'http://localhost:3000/ticketClasses'; private BASE_URL: string = 'http://localhost:8085/api/v1/travel-classes';
getAll(): Observable<FlightClass[]> { getAll(): Observable<FlightClass[]> {
return this.http.get<FlightClass[]>(this.BASE_URL); return this.http.get<FlightClass[]>(this.BASE_URL, { headers });
} }
} }
...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core'; ...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { TicketType } from '../interfaces/ticket-type.interface'; import { TicketType } from '../interfaces/ticket-type.interface';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { headers } from 'src/app/shared/utils/header.util';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class TicketTypeService { export class TicketTypeService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
private BASE_URL: string = 'http://localhost:3000/ticketTypes'; private BASE_URL: string = 'http://localhost:8085/api/v1/ticket-types';
getAll(): Observable<TicketType[]> { getAll(): Observable<TicketType[]> {
return this.http.get<TicketType[]>(this.BASE_URL); return this.http.get<TicketType[]>(this.BASE_URL, { headers });
} }
} }
import { FormGroup, FormControl, Validators } from "@angular/forms"; import { FormGroup, FormControl, Validators } from "@angular/forms";
const nameLenght = { min: 3, max: 20 }; const nameLenght = { min: 3, max: 20 };
const secondNameLenght = { min: 0, max: 20 };
const lastnameLenght = { min: 3, max: 30 }; const lastnameLenght = { min: 3, max: 30 };
const countryLenght = { min: 3, max: 30 }; const countryLenght = { min: 3, max: 30 };
const cityLenght = { min: 3, max: 30 }; const cityLenght = { min: 3, max: 30 };
...@@ -12,7 +11,6 @@ const passwordLenght = { min: 3, max: 45 }; ...@@ -12,7 +11,6 @@ const passwordLenght = { min: 3, max: 45 };
export const PASSENGER_VALIDATORS = new FormGroup({ export const PASSENGER_VALIDATORS = new FormGroup({
name: new FormControl('', [Validators.required, Validators.minLength(nameLenght.min), Validators.maxLength(nameLenght.max)]), name: new FormControl('', [Validators.required, Validators.minLength(nameLenght.min), Validators.maxLength(nameLenght.max)]),
secondName: new FormControl('', [Validators.maxLength(secondNameLenght.max)]),
lastname: new FormControl('', [Validators.required, Validators.minLength(lastnameLenght.min), Validators.maxLength(lastnameLenght.max)]), lastname: new FormControl('', [Validators.required, Validators.minLength(lastnameLenght.min), Validators.maxLength(lastnameLenght.max)]),
country: new FormControl('', [Validators.required, Validators.minLength(countryLenght.min), Validators.maxLength(countryLenght.max)]), country: new FormControl('', [Validators.required, Validators.minLength(countryLenght.min), Validators.maxLength(countryLenght.max)]),
city: new FormControl('', [Validators.required, Validators.minLength(cityLenght.min), Validators.maxLength(cityLenght.max)]), city: new FormControl('', [Validators.required, Validators.minLength(cityLenght.min), Validators.maxLength(cityLenght.max)]),
...@@ -26,8 +24,6 @@ export const getPassengerValidatorLenght = (field: string) => { ...@@ -26,8 +24,6 @@ export const getPassengerValidatorLenght = (field: string) => {
switch (field) { switch (field) {
case 'name': case 'name':
return nameLenght; return nameLenght;
case 'secondName':
return secondNameLenght;
case 'lastname': case 'lastname':
return lastnameLenght; return lastnameLenght;
case 'country': case 'country':
......
import { ReservationStatusCode } from "src/app/agent/interfaces/reservation.interface";
export interface ReservationDetail { export interface ReservationDetail {
id: number; id: number;
origin: string; aiportOrigin: string;
destination: string; airportDestination: string;
date: string; reservationMade: string;
status: ReservationStatusCode; arrivalDate: string;
status: string;
cost: number; cost: number;
} }
...@@ -68,3 +68,15 @@ input:focus + label { ...@@ -68,3 +68,15 @@ input:focus + label {
color: white; color: white;
font-size: 12px; font-size: 12px;
} }
.btn-add {
border: 1px solid #ccc;
color: #676a6c;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
width: 32px;
height: 32px;
box-shadow: 0 5px 5px -3px #0003, 0 8px 10px 1px #00000024, 0 3px 14px 2px #0000001f;
}
...@@ -11,6 +11,16 @@ ...@@ -11,6 +11,16 @@
[onClickItem]="onClickItem"> [onClickItem]="onClickItem">
</shared-table-custom> </shared-table-custom>
<shared-delete-dialog
*ngIf="openDialogDelete"
(onDialogResult)="onDeleteItem($event)">
</shared-delete-dialog>
<shared-confirm-dialog
*ngIf="openDialogCancel"
(onDialogResult)="onCancelItem($event)">
</shared-confirm-dialog>
<shared-dialog <shared-dialog
(onCloseDialog)="onTogleDialogPay()" (onCloseDialog)="onTogleDialogPay()"
[isActivated]="openDialogPay" [isActivated]="openDialogPay"
...@@ -50,7 +60,7 @@ ...@@ -50,7 +60,7 @@
</shared-input-text> </shared-input-text>
</div> </div>
<div class="pay_actions"> <div class="pay_actions">
<button (click)="onTogleDialogPay()" class="btn btn-back"> <button (click)="onSave()" class="btn btn-back">
Cancelar Cancelar
</button> </button>
<button [disabled]="formGroup.invalid" class="btn btn-pay" (click)="onSave()"> <button [disabled]="formGroup.invalid" class="btn btn-pay" (click)="onSave()">
......
...@@ -5,8 +5,7 @@ import { TableAction } from 'src/app/shared/interfaces/table-action.interface'; ...@@ -5,8 +5,7 @@ import { TableAction } from 'src/app/shared/interfaces/table-action.interface';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { FormControl, FormGroup, Validators } from '@angular/forms'; import { FormControl, FormGroup, Validators } from '@angular/forms';
import { ReservationsService } from 'src/app/agent/services/reservations.service'; import { ReservationsService } from 'src/app/agent/services/reservations.service';
import { FlightService } from 'src/app/supervisor/services/flight.service'; import { SecurityService } from 'src/app/security/services/security.service';
import { Reservation } from 'src/app/agent/interfaces/reservation.interface';
@Component({ @Component({
selector: 'passenger-my-reservations', selector: 'passenger-my-reservations',
...@@ -19,22 +18,41 @@ export class MyReservationsComponent implements OnInit { ...@@ -19,22 +18,41 @@ export class MyReservationsComponent implements OnInit {
{ {
title: 'Editar', title: 'Editar',
icon: 'bi-pencil-square', icon: 'bi-pencil-square',
action: (item) => { console.log(item); } disabled: (_) => true,
action: (_) => { }
}, },
{ {
title: 'Eliminar', title: 'Eliminar',
icon: 'bi-trash', icon: 'bi-trash',
action: (item) => { console.log(item); } disabled: (_) => true,
action: (item) => { this.openDialogDelete = !this.openDialogDelete; this.reservationSelected = item; }
},
{
title: "Cancelar",
icon: "bi-x-circle",
disabled: (item) => item.status === 'Pagado' || item.status === 'Cancelado',
action: (item) => { this.openDialogCancel = true; this.reservationSelected = item }
}, },
{ {
title: "Pagar", title: "Pagar",
icon: "bi-cash", icon: "bi-cash",
disabled: (item) => item.status === 'Pagado' || item.status === 'Cancelado',
action: (item) => { this.onTogleDialogPay(); this.reservationSelected = item; } action: (item) => { this.onTogleDialogPay(); this.reservationSelected = item; }
} }
]; ];
public cancelReservation(item: any): void {
this.reservationService.cancelReservation(item.id)
.subscribe( _ => {
this.getAll();
})
}
public reservationSelected: ReservationDetail | null = null; public reservationSelected: ReservationDetail | null = null;
public reservation: Reservation | null = null; public reservation: ReservationDetail | null = null;
public openDialogDelete: boolean = false;
public openDialogCancel: boolean = false;
public tableModel: TableModel[] = [ public tableModel: TableModel[] = [
{ {
...@@ -42,15 +60,15 @@ export class MyReservationsComponent implements OnInit { ...@@ -42,15 +60,15 @@ export class MyReservationsComponent implements OnInit {
title: '#', title: '#',
}, },
{ {
name: 'origin', name: 'airportOrigin',
title: 'Origen', title: 'Origen',
}, },
{ {
name: 'destination', name: 'airportDestination',
title: 'Destino', title: 'Destino',
}, },
{ {
name: 'date', name: 'reservationMade',
title: 'Fecha', title: 'Fecha',
}, },
{ {
...@@ -59,7 +77,7 @@ export class MyReservationsComponent implements OnInit { ...@@ -59,7 +77,7 @@ export class MyReservationsComponent implements OnInit {
}, },
{ {
name: 'cost', name: 'cost',
title: 'Costo', title: 'Costo (USD)',
} }
] ]
public tableData: ReservationDetail[] = []; public tableData: ReservationDetail[] = [];
...@@ -77,14 +95,13 @@ export class MyReservationsComponent implements OnInit { ...@@ -77,14 +95,13 @@ export class MyReservationsComponent implements OnInit {
}); });
onSave(): void { onSave(): void {
if (this.formGroup.valid && this.reservation && this.reservationSelected) { if (this.formGroup.valid && this.reservationSelected) {
this.reservation.statusCode = 'PROCESANDO_PAGO'; this.reservationService.payReservation(this.reservationSelected.id)
this.reservationSelected.status = 'PROCESANDO_PAGO'; .subscribe( reservation => {
this.reservationService.edit(this.reservationSelected!.id, this.reservation) this.tableData = this.tableData.map(item => item.id === reservation.id ? reservation : item);
.subscribe(() => {
this.formGroup.reset(); this.formGroup.reset();
this.onTogleDialogPay(); this.onTogleDialogPay();
}); })
} }
} }
...@@ -92,26 +109,17 @@ export class MyReservationsComponent implements OnInit { ...@@ -92,26 +109,17 @@ export class MyReservationsComponent implements OnInit {
constructor(private router: Router, constructor(private router: Router,
private reservationService: ReservationsService, private reservationService: ReservationsService,
private flightService: FlightService) {} private securityService: SecurityService) {}
ngOnInit(): void { ngOnInit(): void {
this.reservationService.getByPassengerId(4) this.getAll();
}
getAll(): void {
const id = this.securityService.currentUser?.id!;
this.reservationService.getByPassengerId(id)
.subscribe(response => { .subscribe(response => {
response.forEach(reservation => { this.tableData = response;
this.reservation = reservation;
this.flightService.getById(reservation.flightId)
.subscribe((flight) => {
const reservationDetail: ReservationDetail = {
id: reservation.id!,
origin: flight.airportOrigin,
destination: flight.airportDestination,
date: reservation.dateReservationMade,
status: reservation.statusCode,
cost: flight.costs[0].cost
}
this.tableData.push(reservationDetail);
})
})
}) })
} }
...@@ -122,4 +130,21 @@ export class MyReservationsComponent implements OnInit { ...@@ -122,4 +130,21 @@ export class MyReservationsComponent implements OnInit {
onTogleDialogPay(): void { onTogleDialogPay(): void {
this.openDialogPay = !this.openDialogPay; this.openDialogPay = !this.openDialogPay;
} }
onDeleteItem(result: boolean): void {
if (result) {
console.log(this.reservationSelected?.id!);
// this.reservationService.delete(this.reservationSelected?.id!)
// .subscribe(() => {
// this.tableData = this.tableData.filter(item => item.id !== this.reservationSelected?.id!);
// this.openDialogDelete = false;
// })
} this.openDialogDelete = false;
}
onCancelItem(result: boolean): void {
if (result) {
this.cancelReservation(this.reservationSelected?.id!);
} this.openDialogCancel = false;
}
} }
// To parse this data:
//
// import { Convert, AgentAuthorize } from "./file";
//
// const agentAuthorize = Convert.toAgentAuthorize(json);
//
// These functions will throw an error if the JSON doesn't
// match the expected interface, even if the JSON is valid.
export interface AgentAuthorize {
name: string;
lastname: string;
detail: string;
email: string;
password: string;
userId: number;
id: number;
user: User;
}
export interface User {
id: number;
email: string;
password: string;
role: string;
}
// Converts JSON strings to/from your types
// and asserts the results of JSON.parse at runtime
export class Convert {
public static toAgentAuthorize(json: string): AgentAuthorize {
return cast(JSON.parse(json), r("AgentAuthorize"));
}
public static agentAuthorizeToJson(value: AgentAuthorize): string {
return JSON.stringify(uncast(value, r("AgentAuthorize")), null, 2);
}
}
function invalidValue(typ: any, val: any, key: any, parent: any = ''): never {
const prettyTyp = prettyTypeName(typ);
const parentText = parent ? ` on ${parent}` : '';
const keyText = key ? ` for key "${key}"` : '';
throw Error(`Invalid value${keyText}${parentText}. Expected ${prettyTyp} but got ${JSON.stringify(val)}`);
}
function prettyTypeName(typ: any): string {
if (Array.isArray(typ)) {
if (typ.length === 2 && typ[0] === undefined) {
return `an optional ${prettyTypeName(typ[1])}`;
} else {
return `one of [${typ.map(a => { return prettyTypeName(a); }).join(", ")}]`;
}
} else if (typeof typ === "object" && typ.literal !== undefined) {
return typ.literal;
} else {
return typeof typ;
}
}
function jsonToJSProps(typ: any): any {
if (typ.jsonToJS === undefined) {
const map: any = {};
typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ });
typ.jsonToJS = map;
}
return typ.jsonToJS;
}
function jsToJSONProps(typ: any): any {
if (typ.jsToJSON === undefined) {
const map: any = {};
typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ });
typ.jsToJSON = map;
}
return typ.jsToJSON;
}
function transform(val: any, typ: any, getProps: any, key: any = '', parent: any = ''): any {
function transformPrimitive(typ: string, val: any): any {
if (typeof typ === typeof val) return val;
return invalidValue(typ, val, key, parent);
}
function transformUnion(typs: any[], val: any): any {
// val must validate against one typ in typs
const l = typs.length;
for (let i = 0; i < l; i++) {
const typ = typs[i];
try {
return transform(val, typ, getProps);
} catch (_) {}
}
return invalidValue(typs, val, key, parent);
}
function transformEnum(cases: string[], val: any): any {
if (cases.indexOf(val) !== -1) return val;
return invalidValue(cases.map(a => { return l(a); }), val, key, parent);
}
function transformArray(typ: any, val: any): any {
// val must be an array with no invalid elements
if (!Array.isArray(val)) return invalidValue(l("array"), val, key, parent);
return val.map(el => transform(el, typ, getProps));
}
function transformDate(val: any): any {
if (val === null) {
return null;
}
const d = new Date(val);
if (isNaN(d.valueOf())) {
return invalidValue(l("Date"), val, key, parent);
}
return d;
}
function transformObject(props: { [k: string]: any }, additional: any, val: any): any {
if (val === null || typeof val !== "object" || Array.isArray(val)) {
return invalidValue(l(ref || "object"), val, key, parent);
}
const result: any = {};
Object.getOwnPropertyNames(props).forEach(key => {
const prop = props[key];
const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined;
result[prop.key] = transform(v, prop.typ, getProps, key, ref);
});
Object.getOwnPropertyNames(val).forEach(key => {
if (!Object.prototype.hasOwnProperty.call(props, key)) {
result[key] = transform(val[key], additional, getProps, key, ref);
}
});
return result;
}
if (typ === "any") return val;
if (typ === null) {
if (val === null) return val;
return invalidValue(typ, val, key, parent);
}
if (typ === false) return invalidValue(typ, val, key, parent);
let ref: any = undefined;
while (typeof typ === "object" && typ.ref !== undefined) {
ref = typ.ref;
typ = typeMap[typ.ref];
}
if (Array.isArray(typ)) return transformEnum(typ, val);
if (typeof typ === "object") {
return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val)
: typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val)
: typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val)
: invalidValue(typ, val, key, parent);
}
// Numbers can be parsed by Date but shouldn't be.
if (typ === Date && typeof val !== "number") return transformDate(val);
return transformPrimitive(typ, val);
}
function cast<T>(val: any, typ: any): T {
return transform(val, typ, jsonToJSProps);
}
function uncast<T>(val: T, typ: any): any {
return transform(val, typ, jsToJSONProps);
}
function l(typ: any) {
return { literal: typ };
}
function a(typ: any) {
return { arrayItems: typ };
}
function u(...typs: any[]) {
return { unionMembers: typs };
}
function o(props: any[], additional: any) {
return { props, additional };
}
function m(additional: any) {
return { props: [], additional };
}
function r(name: string) {
return { ref: name };
}
const typeMap: any = {
"AgentAuthorize": o([
{ json: "name", js: "name", typ: "" },
{ json: "lastname", js: "lastname", typ: "" },
{ json: "detail", js: "detail", typ: "" },
{ json: "email", js: "email", typ: "" },
{ json: "password", js: "password", typ: "" },
{ json: "userId", js: "userId", typ: 0 },
{ json: "id", js: "id", typ: 0 },
{ json: "user", js: "user", typ: r("User") },
], false),
"User": o([
{ json: "id", js: "id", typ: 0 },
{ json: "email", js: "email", typ: "" },
{ json: "password", js: "password", typ: "" },
{ json: "role", js: "role", typ: "" },
], false),
};
// To parse this data:
//
// import { Convert, PassengerAuthorize } from "./file";
//
// const passengerAuthorize = Convert.toPassengerAuthorize(json);
//
// These functions will throw an error if the JSON doesn't
// match the expected interface, even if the JSON is valid.
export interface PassengerAuthorize {
name: string;
secondName: string;
lastname: string;
country: string;
city: string;
address: string;
phone: string;
email: string;
password: string;
userId: number;
id: number;
user: User;
}
export interface User {
id: number;
email: string;
password: string;
role: string;
}
// Converts JSON strings to/from your types
// and asserts the results of JSON.parse at runtime
export class Convert {
public static toPassengerAuthorize(json: string): PassengerAuthorize {
return cast(JSON.parse(json), r("PassengerAuthorize"));
}
public static passengerAuthorizeToJson(value: PassengerAuthorize): string {
return JSON.stringify(uncast(value, r("PassengerAuthorize")), null, 2);
}
}
function invalidValue(typ: any, val: any, key: any, parent: any = ''): never {
const prettyTyp = prettyTypeName(typ);
const parentText = parent ? ` on ${parent}` : '';
const keyText = key ? ` for key "${key}"` : '';
throw Error(`Invalid value${keyText}${parentText}. Expected ${prettyTyp} but got ${JSON.stringify(val)}`);
}
function prettyTypeName(typ: any): string {
if (Array.isArray(typ)) {
if (typ.length === 2 && typ[0] === undefined) {
return `an optional ${prettyTypeName(typ[1])}`;
} else {
return `one of [${typ.map(a => { return prettyTypeName(a); }).join(", ")}]`;
}
} else if (typeof typ === "object" && typ.literal !== undefined) {
return typ.literal;
} else {
return typeof typ;
}
}
function jsonToJSProps(typ: any): any {
if (typ.jsonToJS === undefined) {
const map: any = {};
typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ });
typ.jsonToJS = map;
}
return typ.jsonToJS;
}
function jsToJSONProps(typ: any): any {
if (typ.jsToJSON === undefined) {
const map: any = {};
typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ });
typ.jsToJSON = map;
}
return typ.jsToJSON;
}
function transform(val: any, typ: any, getProps: any, key: any = '', parent: any = ''): any {
function transformPrimitive(typ: string, val: any): any {
if (typeof typ === typeof val) return val;
return invalidValue(typ, val, key, parent);
}
function transformUnion(typs: any[], val: any): any {
// val must validate against one typ in typs
const l = typs.length;
for (let i = 0; i < l; i++) {
const typ = typs[i];
try {
return transform(val, typ, getProps);
} catch (_) {}
}
return invalidValue(typs, val, key, parent);
}
function transformEnum(cases: string[], val: any): any {
if (cases.indexOf(val) !== -1) return val;
return invalidValue(cases.map(a => { return l(a); }), val, key, parent);
}
function transformArray(typ: any, val: any): any {
// val must be an array with no invalid elements
if (!Array.isArray(val)) return invalidValue(l("array"), val, key, parent);
return val.map(el => transform(el, typ, getProps));
}
function transformDate(val: any): any {
if (val === null) {
return null;
}
const d = new Date(val);
if (isNaN(d.valueOf())) {
return invalidValue(l("Date"), val, key, parent);
}
return d;
}
function transformObject(props: { [k: string]: any }, additional: any, val: any): any {
if (val === null || typeof val !== "object" || Array.isArray(val)) {
return invalidValue(l(ref || "object"), val, key, parent);
}
const result: any = {};
Object.getOwnPropertyNames(props).forEach(key => {
const prop = props[key];
const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined;
result[prop.key] = transform(v, prop.typ, getProps, key, ref);
});
Object.getOwnPropertyNames(val).forEach(key => {
if (!Object.prototype.hasOwnProperty.call(props, key)) {
result[key] = transform(val[key], additional, getProps, key, ref);
}
});
return result;
}
if (typ === "any") return val;
if (typ === null) {
if (val === null) return val;
return invalidValue(typ, val, key, parent);
}
if (typ === false) return invalidValue(typ, val, key, parent);
let ref: any = undefined;
while (typeof typ === "object" && typ.ref !== undefined) {
ref = typ.ref;
typ = typeMap[typ.ref];
}
if (Array.isArray(typ)) return transformEnum(typ, val);
if (typeof typ === "object") {
return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val)
: typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val)
: typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val)
: invalidValue(typ, val, key, parent);
}
// Numbers can be parsed by Date but shouldn't be.
if (typ === Date && typeof val !== "number") return transformDate(val);
return transformPrimitive(typ, val);
}
function cast<T>(val: any, typ: any): T {
return transform(val, typ, jsonToJSProps);
}
function uncast<T>(val: T, typ: any): any {
return transform(val, typ, jsToJSONProps);
}
function l(typ: any) {
return { literal: typ };
}
function a(typ: any) {
return { arrayItems: typ };
}
function u(...typs: any[]) {
return { unionMembers: typs };
}
function o(props: any[], additional: any) {
return { props, additional };
}
function m(additional: any) {
return { props: [], additional };
}
function r(name: string) {
return { ref: name };
}
const typeMap: any = {
"PassengerAuthorize": o([
{ json: "name", js: "name", typ: "" },
{ json: "secondName", js: "secondName", typ: "" },
{ json: "lastname", js: "lastname", typ: "" },
{ json: "country", js: "country", typ: "" },
{ json: "city", js: "city", typ: "" },
{ json: "address", js: "address", typ: "" },
{ json: "phone", js: "phone", typ: "" },
{ json: "email", js: "email", typ: "" },
{ json: "password", js: "password", typ: "" },
{ json: "userId", js: "userId", typ: 0 },
{ json: "id", js: "id", typ: 0 },
{ json: "user", js: "user", typ: r("User") },
], false),
"User": o([
{ json: "id", js: "id", typ: 0 },
{ json: "email", js: "email", typ: "" },
{ json: "password", js: "password", typ: "" },
{ json: "role", js: "role", typ: "" },
], false),
};
export interface SecurityResponse { export interface SecurityResponse {
accessToken: string;
user: User;
}
interface User {
id: number; id: number;
name: string;
lastname: string;
email: string; email: string;
role: string; role: string;
} }
// To parse this data:
//
// import { Convert, Supervisor } from "./file";
//
// const supervisor = Convert.toSupervisor(json);
//
// These functions will throw an error if the JSON doesn't
// match the expected interface, even if the JSON is valid.
export interface SupervisorAuthorize {
id: number;
name: string;
lastname: string;
detail: string;
userId: number;
user: User;
}
export interface User {
id: number;
email: string;
password: string;
role: string;
}
// Converts JSON strings to/from your types
// and asserts the results of JSON.parse at runtime
export class Convert {
public static toSupervisor(json: string): SupervisorAuthorize {
return cast(JSON.parse(json), r("Supervisor"));
}
public static supervisorToJson(value: SupervisorAuthorize): string {
return JSON.stringify(uncast(value, r("Supervisor")), null, 2);
}
}
function invalidValue(typ: any, val: any, key: any, parent: any = ''): never {
const prettyTyp = prettyTypeName(typ);
const parentText = parent ? ` on ${parent}` : '';
const keyText = key ? ` for key "${key}"` : '';
throw Error(`Invalid value${keyText}${parentText}. Expected ${prettyTyp} but got ${JSON.stringify(val)}`);
}
function prettyTypeName(typ: any): string {
if (Array.isArray(typ)) {
if (typ.length === 2 && typ[0] === undefined) {
return `an optional ${prettyTypeName(typ[1])}`;
} else {
return `one of [${typ.map(a => { return prettyTypeName(a); }).join(", ")}]`;
}
} else if (typeof typ === "object" && typ.literal !== undefined) {
return typ.literal;
} else {
return typeof typ;
}
}
function jsonToJSProps(typ: any): any {
if (typ.jsonToJS === undefined) {
const map: any = {};
typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ });
typ.jsonToJS = map;
}
return typ.jsonToJS;
}
function jsToJSONProps(typ: any): any {
if (typ.jsToJSON === undefined) {
const map: any = {};
typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ });
typ.jsToJSON = map;
}
return typ.jsToJSON;
}
function transform(val: any, typ: any, getProps: any, key: any = '', parent: any = ''): any {
function transformPrimitive(typ: string, val: any): any {
if (typeof typ === typeof val) return val;
return invalidValue(typ, val, key, parent);
}
function transformUnion(typs: any[], val: any): any {
// val must validate against one typ in typs
const l = typs.length;
for (let i = 0; i < l; i++) {
const typ = typs[i];
try {
return transform(val, typ, getProps);
} catch (_) {}
}
return invalidValue(typs, val, key, parent);
}
function transformEnum(cases: string[], val: any): any {
if (cases.indexOf(val) !== -1) return val;
return invalidValue(cases.map(a => { return l(a); }), val, key, parent);
}
function transformArray(typ: any, val: any): any {
// val must be an array with no invalid elements
if (!Array.isArray(val)) return invalidValue(l("array"), val, key, parent);
return val.map(el => transform(el, typ, getProps));
}
function transformDate(val: any): any {
if (val === null) {
return null;
}
const d = new Date(val);
if (isNaN(d.valueOf())) {
return invalidValue(l("Date"), val, key, parent);
}
return d;
}
function transformObject(props: { [k: string]: any }, additional: any, val: any): any {
if (val === null || typeof val !== "object" || Array.isArray(val)) {
return invalidValue(l(ref || "object"), val, key, parent);
}
const result: any = {};
Object.getOwnPropertyNames(props).forEach(key => {
const prop = props[key];
const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined;
result[prop.key] = transform(v, prop.typ, getProps, key, ref);
});
Object.getOwnPropertyNames(val).forEach(key => {
if (!Object.prototype.hasOwnProperty.call(props, key)) {
result[key] = transform(val[key], additional, getProps, key, ref);
}
});
return result;
}
if (typ === "any") return val;
if (typ === null) {
if (val === null) return val;
return invalidValue(typ, val, key, parent);
}
if (typ === false) return invalidValue(typ, val, key, parent);
let ref: any = undefined;
while (typeof typ === "object" && typ.ref !== undefined) {
ref = typ.ref;
typ = typeMap[typ.ref];
}
if (Array.isArray(typ)) return transformEnum(typ, val);
if (typeof typ === "object") {
return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val)
: typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val)
: typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val)
: invalidValue(typ, val, key, parent);
}
// Numbers can be parsed by Date but shouldn't be.
if (typ === Date && typeof val !== "number") return transformDate(val);
return transformPrimitive(typ, val);
}
function cast<T>(val: any, typ: any): T {
return transform(val, typ, jsonToJSProps);
}
function uncast<T>(val: T, typ: any): any {
return transform(val, typ, jsToJSONProps);
}
function l(typ: any) {
return { literal: typ };
}
function a(typ: any) {
return { arrayItems: typ };
}
function u(...typs: any[]) {
return { unionMembers: typs };
}
function o(props: any[], additional: any) {
return { props, additional };
}
function m(additional: any) {
return { props: [], additional };
}
function r(name: string) {
return { ref: name };
}
const typeMap: any = {
"Supervisor": o([
{ json: "id", js: "id", typ: 0 },
{ json: "name", js: "name", typ: "" },
{ json: "lastname", js: "lastname", typ: "" },
{ json: "detail", js: "detail", typ: "" },
{ json: "userId", js: "userId", typ: 0 },
{ json: "user", js: "user", typ: r("User") },
], false),
"User": o([
{ json: "id", js: "id", typ: 0 },
{ json: "email", js: "email", typ: "" },
{ json: "password", js: "password", typ: "" },
{ json: "role", js: "role", typ: "" },
], false),
};
export interface UserLogged {
id: number;
name: string;
lastname: string;
email: string;
token: string;
role: string;
}
import { Component } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms'; import { FormControl, FormGroup, Validators } from '@angular/forms';
import { SecurityService } from '../../services/security.service'; import { SecurityService } from '../../services/security.service';
import { SecurityCredentials } from '../../models/security-credentials.interface'; import { SecurityCredentials } from '../../models/security-credentials.interface';
import { SecurityResponse } from '../../models/security-response.interface'; import { SecurityResponse } from '../../models/security-response.interface';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { UserLogged } from '../../models/user-logged.interface';
import { SupervisorAuthorize } from '../../models/supervisor-authorize.interface';
import { AgentAuthorize } from '../../models/agent-authorize.interface';
import { PassengerAuthorize } from '../../models/passenger-authorize.interface';
@Component({ @Component({
selector: 'app-sign-in', selector: 'app-sign-in',
templateUrl: './sign-in.component.html', templateUrl: './sign-in.component.html',
styleUrls: ['./sign-in.component.css'] styleUrls: ['./sign-in.component.css']
}) })
export class SignInComponent { export class SignInComponent implements OnInit {
ngOnInit(): void {
if (this.securityService.currentUser) {
this.redirectToMainPage(this.securityService.currentUser.role);
}
}
public lenguage: string = 'es'; public lenguage: string = 'es';
public lenguages: any[] = [ public lenguages: any[] = [
...@@ -50,7 +53,6 @@ export class SignInComponent { ...@@ -50,7 +53,6 @@ export class SignInComponent {
}); });
public showError: boolean = false; public showError: boolean = false;
public securityResponse: SecurityResponse | null = null;
changeLenguage(lenguage: string) { changeLenguage(lenguage: string) {
this.lenguage = lenguage; this.lenguage = lenguage;
...@@ -62,71 +64,28 @@ export class SignInComponent { ...@@ -62,71 +64,28 @@ export class SignInComponent {
const credentials: SecurityCredentials = this.signInForm.value; const credentials: SecurityCredentials = this.signInForm.value;
this.securityService.login(credentials) this.securityService.login(credentials)
.subscribe(securityResponse => { .subscribe(securityResponse => {
this.redirectAndSaveLocalStorage(securityResponse); this.saveToLocalStorage(securityResponse);
}); this.redirectToMainPage(securityResponse.role);
}, _ => this.showError = true);
} else this.showError = true; } else this.showError = true;
} }
redirectAndSaveLocalStorage(securityResponse: SecurityResponse): void { redirectToMainPage(role: string): void {
switch(securityResponse.user.role) { switch(role.toLowerCase()) {
case 'supervisor': case 'supervisor':
this.securityService.getSupervisorByUserId(securityResponse.user.id) this.router.navigate(['/supervisors']);
.subscribe(supervisors => {
this.supervisorSaveLocalStorage(supervisors[0], securityResponse);
this.router.navigate(['/supervisors']);
});
break; break;
case 'agent': case 'agent':
this.securityService.getAgentByUserId(securityResponse.user.id) this.router.navigate(['/agents']);
.subscribe(agents => {
this.agentSaveLocalStorage(agents[0], securityResponse);
this.router.navigate(['/agents']);
});
break; break;
case 'passenger': case 'passenger':
this.securityService.getPassengerByUserId(securityResponse.user.id) this.router.navigate(['/passengers']);
.subscribe(passengers => {
this.passengerSaveLocalStorage(passengers[0], securityResponse);
this.router.navigate(['/passengers']);
});
break; break;
} }
} }
supervisorSaveLocalStorage(supervisor: SupervisorAuthorize, securityResponse: SecurityResponse): void { saveToLocalStorage(securityResponse: SecurityResponse): void {
const userLogged: UserLogged = { localStorage.setItem('userLogged', JSON.stringify(securityResponse));
id: supervisor.id,
name: supervisor.name,
lastname: supervisor.lastname,
email: supervisor.user.email,
role: supervisor.user.role,
token: securityResponse.accessToken
}
localStorage.setItem('userLogged', JSON.stringify(userLogged));
}
agentSaveLocalStorage(agent: AgentAuthorize, securityResponse: SecurityResponse): void {
const userLogged: UserLogged = {
id: agent.id,
name: agent.name,
lastname: agent.lastname,
email: agent.user.email,
role: agent.user.role,
token: securityResponse.accessToken
}
localStorage.setItem('userLogged', JSON.stringify(userLogged));
}
passengerSaveLocalStorage(passenger: PassengerAuthorize, securityResponse: SecurityResponse): void {
const userLogged: UserLogged = {
id: passenger.id,
name: passenger.name,
lastname: passenger.lastname,
email: passenger.user.email,
role: passenger.user.role,
token: securityResponse.accessToken
}
localStorage.setItem('userLogged', JSON.stringify(userLogged));
} }
} }
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { SecurityCredentials } from '../models/security-credentials.interface'; import { SecurityCredentials } from '../models/security-credentials.interface';
import { SecurityResponse } from '../models/security-response.interface'; import { SecurityResponse } from '../models/security-response.interface';
import { Observable, of, tap } from 'rxjs'; import { Observable } from 'rxjs';
import { SupervisorAuthorize } from '../models/supervisor-authorize.interface';
import { Passenger } from 'src/app/agent/interfaces/passenger.interface';
import { PassengerAuthorize } from '../models/passenger-authorize.interface';
import { AgentAuthorize } from '../models/agent-authorize.interface';
import { UserLogged } from '../models/user-logged.interface';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class SecurityService { export class SecurityService {
constructor(private http: HttpClient, private router: Router) { } constructor(private http: HttpClient, private router: Router) { }
URL_BASE: string = 'http://localhost:3000/'; URL_BASE: string = 'http://localhost:8085/api/v1/auth/';
get currentUser(): UserLogged | null { get currentUser(): SecurityResponse | null {
const userLogged: UserLogged | null = JSON.parse(localStorage.getItem('userLogged') || 'null'); const userLocalStorage = localStorage.getItem('userLogged');
return userLogged; if (userLocalStorage == null) return null;
return JSON.parse(userLocalStorage);
} }
login(securityCredentials: SecurityCredentials): Observable<SecurityResponse> { login(securityCredentials: SecurityCredentials): Observable<SecurityResponse> {
return this.http.post<SecurityResponse>(this.URL_BASE + 'signin', securityCredentials); return this.http.post<SecurityResponse>(this.URL_BASE + 'sign-in', securityCredentials);
}
loguot(): void {
localStorage.removeItem('userLogged');
this.router.navigate(['/sign-in']);
} }
getSupervisorByUserId(userId: number): Observable<SupervisorAuthorize[]> { signup(securityCredentials: SecurityCredentials): Observable<SecurityResponse> {
return this.http.get<SupervisorAuthorize[]>(this.URL_BASE + 'supervisors?userId=' + userId + '&_expand=user'); return this.http.post<SecurityResponse>(this.URL_BASE + 'sign-up', securityCredentials);
} }
getPassengerByUserId(userId: number): Observable<PassengerAuthorize[]> { logout(): void {
return this.http.get<PassengerAuthorize[]>(this.URL_BASE + 'passengers?userId=' + userId + '&_expand=user'); localStorage.removeItem('userLogged');
} this.router.navigate(['/sign-in']);
getAgentByUserId(userId: number): Observable<AgentAuthorize[]> {
return this.http.get<AgentAuthorize[]>(this.URL_BASE + 'agents?userId=' + userId + '&_expand=user');
} }
} }
.background {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, .5);
display: flex;
justify-content: center;
align-items: center;
}
.rm-card {
background-color: white;
padding: 10px 20px;
border-radius: 5px;
}
.rm-header {
font-size: 24px;
display: flex;
align-items: center;
}
.rm-header i {
color: red;
font-size: 28px;
margin-right: 10px;
}
.btn-action {
font-weight: 600;
font-size: 15px;
}
.btn-action-active {
background-color: #afafaf;
}
.btn-action:hover {
background-color: #ebe9e9;
}
<div class="background">
<div class="rm-card">
<div class="rm-header">
<i [ngClass]="['bi', icon]"></i>
<span>{{ title }}</span>
</div>
<hr>
<p>{{ message }}</p>
<hr>
<div class="rm-actions d-flex gap-2">
<button (click)="onEmitDeleted(false)" class="btn btn-action btn-action-active">No</button>
<button (click)="onEmitDeleted(true)" class="btn btn-action">Si</button>
</div>
</div>
</div>
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'shared-confirm-dialog',
templateUrl: './confirm-dialog.component.html',
styleUrls: ['./confirm-dialog.component.css']
})
export class ConfirmDialogComponent {
constructor(private router: Router) { }
@Output()
public onDialogResult: EventEmitter<boolean> = new EventEmitter();
@Input()
public title: string = 'Titulo';
@Input()
public message: string = '¿Es es su mensaje?';
@Input()
public icon: string = 'bi-question-circle';
onEmitDeleted(result: boolean): void {
this.onDialogResult.emit(result);
}
}
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, Input, Output } from '@angular/core';
import { ResultDelete } from '../../interfaces/result-delete.interface'; import { ResultDelete } from '../../interfaces/result-delete.interface';
import { Router } from '@angular/router';
@Component({ @Component({
selector: 'shared-delete-dialog', selector: 'shared-delete-dialog',
...@@ -8,6 +9,8 @@ import { ResultDelete } from '../../interfaces/result-delete.interface'; ...@@ -8,6 +9,8 @@ import { ResultDelete } from '../../interfaces/result-delete.interface';
}) })
export class DeleteDialogComponent { export class DeleteDialogComponent {
constructor(private router: Router) { }
@Output() @Output()
public onDialogResult: EventEmitter<boolean> = new EventEmitter(); public onDialogResult: EventEmitter<boolean> = new EventEmitter();
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
.field { .field {
position: relative; position: relative;
padding-top: 10px; padding-top: 7px;
} }
.field input { .field input {
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
} }
.field input:focus { .field input:focus {
border-bottom: 3px solid #3f51b5; border-bottom: 1px solid #3f51b5;
} }
.field label { .field label {
...@@ -26,25 +26,26 @@ ...@@ -26,25 +26,26 @@
left: 4px; left: 4px;
pointer-events: none; pointer-events: none;
transition: 0.2s; transition: 0.2s;
font-size: 12px; font-size: 10px;
} }
.field input:focus + label { .field input:focus + label {
top: 0; top: 0;
left: 4px; left: 4px;
font-size: 12px; font-size: 10px;
color: #3f51b5; color: #3f51b5;
} }
.field input + label { .field input + label {
top: 0; top: 0;
left: 4px; left: 4px;
font-size: 12px; font-size: 10px;
color: #ccc; color: #ccc;
} }
.box-errors { .box-errors {
line-height: 12px; line-height: 10px;
height: 10px;
} }
.errors { .errors {
......
...@@ -31,10 +31,13 @@ export class InputCalendarComponent { ...@@ -31,10 +31,13 @@ export class InputCalendarComponent {
switch (key) { switch (key) {
case 'required': case 'required':
return 'Este campo es requerido'; return 'Este campo es requerido';
case 'isValid': case 'isInvalid':
return 'Fecha partida debe ser mayor a la fecha de llegada'; return 'Fecha partida debe ser mayor a la fecha de llegada';
case 'existCost':
return 'Ya existe un costo para esta fecha';
} }
} }
return null; return null;
} }
} }
.pay_fields {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
.pay_actions {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 10px;
margin-top: 10px;
border-top: 1px solid gray;
}
.pay__field {
display: flex;
flex-direction: column;
position: relative;
padding-top: 15px;
box-sizing: border-box;
height: 38.8px;
}
.pay__field label {
position: absolute;
left: 4px;
font-size: 12px;
color: #ccc;
pointer-events: none;
transition: 0.4s;
}
.pay__field input {
outline: none;
border: 0;
border-bottom: 1px solid #ccc;
font-size: 10px;
padding-left: 4px;
color: #8f8e8e;
}
.pay__field span {
position: absolute;
bottom: 6px;
right: 3px;
font-size: 14px;
}
input:focus + label {
top: 0;
left: 4px;
color: #3f51b5;
font-size: 10px;
}
.pay__field input:focus {
border-bottom: 3px solid #3f51b5;
}
.pay__field .label-top {
top: 0;
left: 4px;
font-size: 10px;
}
.pay__card, .pay__owner {
grid-column: 1 / 3;
}
.input__validation {
display: flex;
}
.input__validation span {
font-size: 10px;
}
.field__container {
height: 53.8px;
}
.pay__field input::-webkit {
display: none;
}
<div class="field__container">
<div class="pay__field pay__card">
<input
[formControl]="control!"
[name]="name"
[id]="name"
#input>
<label [ngClass]="input.value.length > 0 ? 'label-top' : ''" [for]="name">{{ label }}</label>
<span class="bi bi-currency-dollar"></span>
</div>
<div [ngClass]="['input__validation', isInputValid() && input.value.length > 0 ? 'justify-content-between' : input.value.length > 0 ? 'justify-content-end' : 'justify-content-start']">
<span *ngIf="isInputValid()" class="text-danger">{{ getFieldError() }}</span>
</div>
</div>
import { Component, Input } from '@angular/core';
import { FormControl } from '@angular/forms';
@Component({
selector: 'shared-input-currency',
templateUrl: './input-currency.component.html',
styleUrls: ['./input-currency.component.css']
})
export class InputCurrencyComponent {
@Input()
public label: string = '';
@Input()
public name: string = '';
@Input()
public control?: FormControl<number | null>;
isInputValid(): boolean | null {
return this.control? this.control?.errors && this.control?.touched : null;
}
getFieldError(): string | null {
const errors = this.control?.errors || {};
for (const key of Object.keys(errors)) {
switch (key) {
case 'required':
return 'Este campo es requerido';
case 'numberNegative':
return 'El valor no puede ser negativo';
case 'numberZero':
return 'El valor no puede ser cero';
}
}
return null;
}
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: relative; position: relative;
padding-top: 15px; padding-top: 10px;
box-sizing: border-box; box-sizing: border-box;
} }
...@@ -31,17 +31,18 @@ select:focus + label { ...@@ -31,17 +31,18 @@ select:focus + label {
} }
.pay__field select:focus { .pay__field select:focus {
border-bottom: 3px solid #3f51b5; border-bottom: 1px solid #3f51b5;
} }
.pay__field .label-top { .pay__field .label-top {
top: 0; top: 0;
left: 4px; left: 4px;
font-size: 12px; font-size: 10px;
} }
.box-errors { .box-errors {
line-height: 10px; line-height: 10px;
height: 10px;
} }
.errors { .errors {
......
<div class="field__container"> <div class="field__container">
<div class="pay__field pay__card"> <div class="pay__field pay__card">
<select [formControl]="control" [value]="control.value" [ngClass]="['field-select']" id="field-date-start"> <select [formControl]="control" [ngClass]="['field-select', 'disabled']" id="field-date-start">
<option *ngFor="let item of data" [value]="item.value">{{ item.text }}</option> <option *ngFor="let item of data" [value]="item.value">{{ item.text }}</option>
</select> </select>
<label [ngClass]="[control.value ? 'label-top' : '']" for="field-name">{{ name }} *</label> <label [ngClass]="[control.value ? 'label-top' : '']" for="field-name">{{ name }} *</label>
......
...@@ -16,7 +16,7 @@ export class InputDropdownComponent { ...@@ -16,7 +16,7 @@ export class InputDropdownComponent {
public data: DropdownElement[] = [] public data: DropdownElement[] = []
@Input() @Input()
public control: FormControl<string | null> = new FormControl<string | null>(null); public control: FormControl<number | null> = new FormControl(null);
isInputValid(): boolean | null { isInputValid(): boolean | null {
return this.control? this.control?.errors && this.control?.touched : null; return this.control? this.control?.errors && this.control?.touched : null;
...@@ -29,8 +29,10 @@ export class InputDropdownComponent { ...@@ -29,8 +29,10 @@ export class InputDropdownComponent {
switch (key) { switch (key) {
case 'required': case 'required':
return 'Este campo es requerido'; return 'Este campo es requerido';
case 'isValid': case 'airportEqual':
return 'El aeropuerto de partida no puede ser igual al de destino'; return 'El aeropuerto destino debe ser diferente al de origen';
case 'airportOrigin':
return 'El aeropuerto destino debe ser diferente al de origen';
} }
} }
return null; return null;
......
.input__container { .input__container {
position: relative; position: relative;
display: flex; display: flex;
padding-top: 12px; padding-top: 10px;
} }
.input__container button { .input__container button {
...@@ -11,12 +11,13 @@ ...@@ -11,12 +11,13 @@
right: 0; right: 0;
bottom: 0; bottom: 0;
font-size: 12px; font-size: 12px;
z-index: 1;
} }
.input__container label { .input__container label {
position: absolute; position: absolute;
bottom: 1px; bottom: 1px;
left: 4px; left: 6px;
font-size: 12px; font-size: 12px;
color: #ccc; color: #ccc;
pointer-events: none; pointer-events: none;
...@@ -29,10 +30,16 @@ ...@@ -29,10 +30,16 @@
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
outline: none; outline: none;
font-size: 12px; font-size: 12px;
background-color: transparent;
z-index: 2;
color: #8f8e8e; color: #8f8e8e;
padding-left: 4px; padding-left: 4px;
} }
.input__container input:focus {
border-bottom: 1px solid #3f51b5;
}
input:focus + label { input:focus + label {
top: 0; top: 0;
left: 4px; left: 4px;
...@@ -43,5 +50,15 @@ input:focus + label { ...@@ -43,5 +50,15 @@ input:focus + label {
.input__container .label-top { .input__container .label-top {
top: 0; top: 0;
left: 4px; left: 4px;
font-size: 12px; font-size: 10px;
}
.box-errors {
line-height: 10px;
height: 10px;
}
.box-errors span {
font-size: 10px;
line-height: 10px;
} }
<div class="input__container"> <div class="input__container">
<input (focus)="isActivated = true" [readOnly]="true" [value]="value" type="text" [id]="name" #input> <input (focus)="openDialog()" readOnly="true" [value]="getValue()" type="text" [id]="name" #input>
<label [ngClass]="[input.value.length > 0 ? 'label-top' : '']" [for]="name">{{ name }} *</label> <label [ngClass]="[input.value.length > 0 ? 'label-top' : '']" [for]="name">{{ name }} *</label>
<button (click)="openDialog()" type="submit"> <button (click)="openDialog()" type="submit">
<i class="bi bi-search"></i> <i class="bi bi-search"></i>
</button> </button>
</div> </div>
<div class="box-errors"> <div class="box-errors">
<span *ngIf="isInputValid()" class="text-danger errors">{{ getFieldError() }}</span> <span *ngIf="isNotValidInput()" class="text-danger errors">Este campo es requerido</span>
</div> </div>
<shared-dialog [isActivated]="isActivated" title="Buscador" (onCloseDialog)="closeDialog()"> <shared-dialog [isActivated]="isActivated" title="Buscador" (onCloseDialog)="closeDialog()">
<shared-table-search [tableModel]="tableModel" [tableData]="tableData" (onSelect)="selectItem($event)"></shared-table-search> <shared-table-search [tableModel]="tableModel" [tableData]="tableData" (onSelect)="selectItem($event)"></shared-table-search>
......
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { TableModel } from '../../interfaces/table-model.interface'; import { TableModel } from '../../interfaces/table-model.interface';
import { FormControl } from '@angular/forms';
@Component({ @Component({
selector: 'shared-input-selector', selector: 'shared-input-selector',
...@@ -8,6 +9,8 @@ import { TableModel } from '../../interfaces/table-model.interface'; ...@@ -8,6 +9,8 @@ import { TableModel } from '../../interfaces/table-model.interface';
}) })
export class InputSelectorComponent { export class InputSelectorComponent {
constructor() {}
@Input() @Input()
public isActivated: boolean = false; public isActivated: boolean = false;
...@@ -18,16 +21,25 @@ export class InputSelectorComponent { ...@@ -18,16 +21,25 @@ export class InputSelectorComponent {
public tableData: any[] = []; public tableData: any[] = [];
@Input() @Input()
public value: string | null = null; public name: string = '';
@Input() @Input()
public name: string = ''; public fieldShow: string = 'name';
@Output() @Input()
public onSelect: EventEmitter<any> = new EventEmitter<any>(); public control: FormControl<number | null> = new FormControl<number | null>(null);
getValue(): string | null {
return this.control.value != null ? this.tableData.find(item => item.id === this.control.value)?.[this.fieldShow] : '';
}
isNotValidInput(): boolean | null {
return this.control ? this.control.invalid && this.control.touched : false;
}
closeDialog(): void { closeDialog(): void {
this.isActivated = false; this.isActivated = false;
this.control.markAsTouched();
} }
openDialog(): void { openDialog(): void {
...@@ -35,15 +47,7 @@ export class InputSelectorComponent { ...@@ -35,15 +47,7 @@ export class InputSelectorComponent {
} }
selectItem(item: any): void { selectItem(item: any): void {
this.onSelect.emit(item); this.isActivated = false;
this.closeDialog(); this.control.setValue(item.id);
}
isInputValid(): boolean | null {
return this.value ? true : false;
}
getFieldError(): string | null {
return this.isInputValid() ? null : 'Este campo es requerido';
} }
} }
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding-top: 10px; padding-top: 10px;
margin-top: 20px; margin-top: 10px;
border-top: 1px solid gray; border-top: 1px solid gray;
} }
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
outline: none; outline: none;
border: 0; border: 0;
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
font-size: 12px; font-size: 10px;
padding-left: 4px; padding-left: 4px;
color: #8f8e8e; color: #8f8e8e;
} }
...@@ -44,7 +44,7 @@ input:focus + label { ...@@ -44,7 +44,7 @@ input:focus + label {
top: 0; top: 0;
left: 4px; left: 4px;
color: #3f51b5; color: #3f51b5;
font-size: 12px; font-size: 10px;
} }
.pay__field input:focus { .pay__field input:focus {
...@@ -54,7 +54,7 @@ input:focus + label { ...@@ -54,7 +54,7 @@ input:focus + label {
.pay__field .label-top { .pay__field .label-top {
top: 0; top: 0;
left: 4px; left: 4px;
font-size: 12px; font-size: 10px;
} }
.pay__card, .pay__owner { .pay__card, .pay__owner {
......
...@@ -5,6 +5,6 @@ ...@@ -5,6 +5,6 @@
</div> </div>
<div [ngClass]="['input__validation', isInputValid() && input.value.length > 0 ? 'justify-content-between' : input.value.length > 0 ? 'justify-content-end' : 'justify-content-start']"> <div [ngClass]="['input__validation', isInputValid() && input.value.length > 0 ? 'justify-content-between' : input.value.length > 0 ? 'justify-content-end' : 'justify-content-start']">
<span *ngIf="isInputValid()" class="text-danger">{{ getFieldError() }}</span> <span *ngIf="isInputValid()" class="text-danger">{{ getFieldError() }}</span>
<span *ngIf="input.value.length > 0">{{ control?.value?.length}} / {{ maxLength }}</span> <span *ngIf="input.value.length > 0 && type == 'text'">{{ control?.value?.length}} / {{ maxLength }}</span>
</div> </div>
</div> </div>
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
<button class="btn"> <button class="btn">
<i class="bi bi-list-task"></i> <i class="bi bi-list-task"></i>
</button> </button>
<button (click)="goToLogin()" class="btn"> <button (click)="logout()" class="btn">
<i class="bi bi-box-arrow-right"></i> <i class="bi bi-box-arrow-right"></i>
</button> </button>
</div> </div>
......
import { Component, EventEmitter, Output } from '@angular/core'; import { Component, EventEmitter, Output } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { SecurityResponse } from 'src/app/security/models/security-response.interface';
import { SecurityService } from 'src/app/security/services/security.service'; import { SecurityService } from 'src/app/security/services/security.service';
@Component({ @Component({
...@@ -19,14 +20,13 @@ export class NavigationUserComponent { ...@@ -19,14 +20,13 @@ export class NavigationUserComponent {
this.toggleSidebarEvent.emit(); this.toggleSidebarEvent.emit();
} }
get username(): any { get username(): string | null {
const userLogged = this.securityService.currentUser; const userLogged = this.securityService.currentUser;
if (userLogged) { if (userLogged == null) return null;
return `${userLogged.name.toLowerCase().substring(0, 1)}${userLogged.lastname.toLowerCase()}` return `${userLogged.name.toLowerCase().substring(0, 1)}${userLogged.lastname.split(' ')[0].toLowerCase()}`
} return null;
} }
goToLogin(): void { logout(): void {
this.router.navigate(['/sign-in']); this.securityService.logout();
} }
} }
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<td *ngFor="let item of tableModel" (click)="onClickItem(data)" class="table-item">{{ data[item['name']] }}</td> <td *ngFor="let item of tableModel" (click)="onClickItem(data)" class="table-item">{{ data[item['name']] }}</td>
<td class="table-item"> <td class="table-item">
<div class="d-flex justify-content-end"> <div class="d-flex justify-content-end">
<button *ngFor="let action of tableAction" (click)="action.action(data)" class="btn btn-action-table"> <button *ngFor="let action of tableAction" [disabled]="action.disabled(data)" (click)="action.action(data)" class="btn btn-action-table">
<i [ngClass]="['bi', action.icon]"></i> <i [ngClass]="['bi', action.icon]"></i>
<span>{{ action.title }}</span> <span>{{ action.title }}</span>
</button> </button>
...@@ -23,6 +23,10 @@ ...@@ -23,6 +23,10 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
<shared-table-paginator
[tableData]="tableData"
(onChangePagination)="onChangePagination($event)">
</shared-table-paginator>
</div> </div>
</div> </div>
<div class="more-actions"> <div class="more-actions">
......
...@@ -2,6 +2,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; ...@@ -2,6 +2,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
import { TableModel } from '../../interfaces/table-model.interface'; import { TableModel } from '../../interfaces/table-model.interface';
import { TableAction } from '../../interfaces/table-action.interface'; import { TableAction } from '../../interfaces/table-action.interface';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { TablePagination } from '../../interfaces/table-pagination.interface';
@Component({ @Component({
selector: 'shared-table-custom', selector: 'shared-table-custom',
...@@ -17,11 +18,19 @@ export class TableCustomComponent { ...@@ -17,11 +18,19 @@ export class TableCustomComponent {
public onClickItem: (item: any) => void = (item) => { console.log(item); }; public onClickItem: (item: any) => void = (item) => { console.log(item); };
@Input() @Input()
public tableData: any[] = []; public tableData!: any[];
public showTable: any[] = [];
@Input() @Input()
public tableModel: TableModel[] = []; public tableModel: TableModel[] = [];
public pagination: TablePagination = { init: 0, end: 5 };
tableShowElements(): any[] {
return this.tableData.filter((item, index) => index >= this.pagination.init && index < this.pagination.end);
}
@Output() @Output()
public onSelect: EventEmitter<any[]> = new EventEmitter<any[]>(); public onSelect: EventEmitter<any[]> = new EventEmitter<any[]>();
...@@ -30,4 +39,9 @@ export class TableCustomComponent { ...@@ -30,4 +39,9 @@ export class TableCustomComponent {
onSelectRow(row: any): void { onSelectRow(row: any): void {
this.onSelect.emit(row); this.onSelect.emit(row);
} }
onChangePagination(tablePagination: TablePagination) {
this.pagination = tablePagination;
this.showTable = this.tableShowElements();
}
} }
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
import { TablePagination } from '../../interfaces/table-pagination.interface'; import { TablePagination } from '../../interfaces/table-pagination.interface';
import { ThisReceiver } from '@angular/compiler';
@Component({ @Component({
selector: 'shared-table-paginator', selector: 'shared-table-paginator',
......
export interface DropdownElement { export interface DropdownElement {
text: string; text: string;
value: string; value: number;
} }
export interface TableAction { export interface TableAction {
title: string; title: string;
icon: string; icon: string;
disabled: (row: any) => boolean;
action: (row: any) => void; action: (row: any) => void;
} }
...@@ -21,6 +21,8 @@ import { PanelMenuComponent } from './components/panel-menu/panel-menu.component ...@@ -21,6 +21,8 @@ import { PanelMenuComponent } from './components/panel-menu/panel-menu.component
import { TableCustomComponent } from './components/table-custom/table-custom.component'; import { TableCustomComponent } from './components/table-custom/table-custom.component';
import { InputTextComponent } from './components/input-text/input-text.component'; import { InputTextComponent } from './components/input-text/input-text.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { InputCurrencyComponent } from './components/input-currency/input-currency.component';
import { ConfirmDialogComponent } from './components/confirm-dialog/confirm-dialog.component';
...@@ -45,6 +47,8 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; ...@@ -45,6 +47,8 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
PanelMenuComponent, PanelMenuComponent,
TableCustomComponent, TableCustomComponent,
InputTextComponent, InputTextComponent,
InputCurrencyComponent,
ConfirmDialogComponent,
], ],
imports: [ imports: [
CommonModule, CommonModule,
...@@ -70,7 +74,9 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; ...@@ -70,7 +74,9 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
InputDropdownComponent, InputDropdownComponent,
PanelMenuComponent, PanelMenuComponent,
TableCustomComponent, TableCustomComponent,
InputTextComponent InputTextComponent,
InputCurrencyComponent,
ConfirmDialogComponent
] ]
}) })
export class SharedModule { } export class SharedModule { }
import { HttpHeaders } from "@angular/common/http";
const userLogged = localStorage.getItem('userLogged');
const userLoggedParsed = userLogged ? JSON.parse(userLogged) : null;
const token = userLoggedParsed ? userLoggedParsed.token : '';
export const headers = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
});
<div class="row gap-2">
<shared-input-selector
class="col-12"
name="Aerolinea"
[control]="airlineControl"
[tableModel]="airlineModel"
[tableData]="airlines">
</shared-input-selector>
<shared-input-dropdown
class="col-12"
name="Tipo de avion"
[control]="aircraftControl"
[data]="aircrafts">
</shared-input-dropdown>
</div>
<div class="row mt-2">
<shared-input-calendar
class="col-6"
type="date"
name="Fecha de partida"
[control]="departureDateControl">
</shared-input-calendar>
<shared-input-calendar
class="col-6"
name="Fecha de fin"
[control]="arrivalDateControl">
</shared-input-calendar>
</div>
import { Component, Input, OnInit } from '@angular/core';
import { TableModel } from 'src/app/shared/interfaces/table-model.interface';
import { Airline } from '../../interfaces/airline.interface';
import { DropdownElement } from 'src/app/shared/interfaces/dropdown-element-interface';
import { FormControl, Validators } from '@angular/forms';
import { AirlineService } from '../../services/airline.service';
import { AircraftService } from '../../services/aircraft.service';
@Component({
selector: 'supervisor-base-config',
templateUrl: './base-config.component.html',
styleUrls: ['./base-config.component.css']
})
export class BaseConfigComponent implements OnInit {
constructor(private airlineService: AirlineService,
private aircraftService: AircraftService) { }
ngOnInit(): void {
this.getAllAirlines();
this.getAllAircrafts();
}
public airlineModel: TableModel[] = [
{
name: 'id',
title: '#'
},
{
name: 'name',
title: 'Nombre'
},
{
name: 'code',
title: 'Código'
}
]
public airlines: Airline[] = [];
public aircrafts: DropdownElement[] = [];
@Input()
public airlineControl: FormControl<number | null> = new FormControl(null, [Validators.required]);
@Input()
public aircraftControl: FormControl<number | null> = new FormControl(null, [Validators.required]);
@Input()
public departureDateControl: FormControl<string | null> = new FormControl(null, [Validators.required]);
@Input()
public arrivalDateControl: FormControl<string | null> = new FormControl(null, [Validators.required]);
getAllAirlines(): void {
this.airlineService.getAll()
.subscribe(airlines => this.airlines = airlines);
}
getAllAircrafts(): void {
this.aircraftService.getAll()
.subscribe(aircrafts => {
this.aircrafts = aircrafts.map(
aircraft => { return { value: aircraft.id, text: aircraft.name } } );
})
}
}
.btn-add {
border: 1px solid #e0e0e0;
border-radius: 50%;
width: 42px;
height: 42px;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 0 5px 0 #0000001f;
}
.fields {
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: 16px;
}
.actions {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 10px;
margin-top: 30px;
border-top: 1px solid #e0e0e0;
}
.btn-cancel {
border: 1px solid #ccc;
color: #ccc;
font-size: 12px;
}
.btn-accept {
border: 1px solid #1ab394;
background-color: #1ab394;
color: white;
font-size: 12px;
}
.flight__type, .flight__optional{
grid-column: 1 / 3;
}
.currency {
font-size: 12px;
color: #ccc;
border: 1px solid #ccc;
border-radius: 4px;
height: 25px;
padding: 5px;
}
<shared-table-custom
[tableModel]="costModel"
[tableData]="costs">
<div class="more-actions">
<button
(click)="onTogleDialogCost()"
class="btn btn-add">
<i class="bi bi-plus"></i>
</button>
</div>
</shared-table-custom>
<shared-dialog
title="Configurar costos"
(onCloseDialog)="onTogleDialogCost()"
[isActivated]="openDialogCost">
<div class="fields">
<shared-input-calendar
name="Fecha de inicio *"
type="date"
[control]="dateStartControl">
</shared-input-calendar>
<shared-input-calendar
name="Fecha de fin *"
type="date"
[control]="dateEndControl">
</shared-input-calendar>
<shared-input-currency
class="flex-fill"
label="Costo *"
[control]="costControl">
</shared-input-currency>
</div>
<div class="actions">
<button
(click)="onTogleDialogCost()"
class="btn btn-cancel">
Cancelar
</button>
<button
(click)="onSaveCost()"
[disabled]="costsForm.invalid"
class="btn btn-accept">
Aceptar
</button>
</div>
</shared-dialog>
import { Component, Input } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { TableModel } from 'src/app/shared/interfaces/table-model.interface';
import { FlightCost } from '../../interfaces/flight-cost.interface';
@Component({
selector: 'supervisor-costs-config',
templateUrl: './costs-config.component.html',
styleUrls: ['./costs-config.component.css']
})
export class CostsConfigComponent {
public costModel: TableModel[] = [
{
name: 'id',
title: '#'
},
{
name: 'dateStart',
title: 'Fecha Inicio'
},
{
name: 'dateEnd',
title: 'Fecha Fin'
},
{
name: 'cost',
title: 'Costo (USD)'
}
]
@Input()
public costs: FlightCost[] = [];
public openDialogCost: boolean = false;
public dateStartControl: FormControl = new FormControl<string | null>(null, [Validators.required]);
public dateEndControl: FormControl = new FormControl<string | null>(null, [Validators.required]);
public costControl: FormControl = new FormControl<number | null>(null, [Validators.required]);
public costsForm: FormGroup = new FormGroup({
dateStart: this.dateStartControl,
dateEnd: this.dateEndControl,
cost: this.costControl,
}, {
validators: () => {
const dateStart = this.dateStartControl.value as string;
const dateEnd = this.dateEndControl.value as string;
const cost = this.costControl.value as number;
this.crossValidationsDates(dateStart, dateEnd);
this.crossValidationsCost(cost);
return null;
}
});
crossValidationsDates(dateStartString: string, dateEndString: string): void {
const dateStart = new Date(dateStartString);
const dateEnd = new Date(dateEndString);
if (dateStartString == null) this.dateStartControl.setErrors({ required: true });
else if (this.costs.filter(cost => {
const dateStartCost = new Date(cost.dateStart);
const dateEndCost = new Date(cost.dateEnd);
return dateStart.getTime() >= dateStartCost.getTime() && dateStart.getTime() <= dateEndCost.getTime()
}).length > 0) {
this.dateStartControl.setErrors({ existCost: true });
}
if (dateEndString == null) this.dateEndControl.setErrors({ required: true });
else if (dateStart.getTime() >= dateEnd.getTime()) {
this.dateEndControl.setErrors({ isInvalid: true });
} else this.dateEndControl.setErrors(null);
}
crossValidationsCost(cost: number): void {
if (cost === null) this.costControl.setErrors({ required: true });
else if (cost == 0) this.costControl.setErrors({ numberZero: true });
else if (cost < 0) this.costControl.setErrors({ numberNegative: true });
else this.costControl.setErrors(null);
}
onTogleDialogCost(): void {
this.openDialogCost = !this.openDialogCost;
this.costsForm.reset();
}
onSaveCost(): void {
this.costsForm.markAllAsTouched();
if (this.costControl.valid) {
let cost: FlightCost = {
id: this.costs.length + 1,
dateStart: this.dateStartControl.value as string,
dateEnd: this.dateEndControl.value as string,
cost: parseInt(this.costControl.value)
}
this.costs.push(cost);
this.onTogleDialogCost();
}
}
}
.btn-add {
border: 1px solid #e0e0e0;
border-radius: 50%;
width: 42px;
height: 42px;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 0 5px 0 #0000001f;
}
.fields {
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: 16px;
}
.actions {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 10px;
margin-top: 30px;
border-top: 1px solid #e0e0e0;
}
.btn-cancel {
border: 1px solid #ccc;
color: #ccc;
font-size: 12px;
}
.btn-accept {
border: 1px solid #1ab394;
background-color: #1ab394;
color: white;
font-size: 12px;
}
.flight__type, .flight__optional{
grid-column: 1 / 3;
}
<shared-table-custom
[tableModel]="scaleModel"
[tableData]="scales">
<div class="more-actions">
<button (click)="onTogleDialogScale()" class="btn btn-add">
<i class="bi bi-plus"></i>
</button>
</div>
</shared-table-custom>
<shared-dialog
title="Configurar escala"
[isActivated]="openDialogScale"
(onCloseDialog)="onTogleDialogScale()">
<div class="fields">
<shared-input-dropdown
name="Aeropuero de partida"
[control]="airportOriginIdControl"
[data]="airports">
</shared-input-dropdown>
<shared-input-dropdown
name="Aeropuero de llegada"
[control]="airportDestinationIdControl"
[data]="airports">
</shared-input-dropdown>
<shared-input-calendar
name="Hora de partida"
type="datetime-local"
[control]="departureDateTimeControl">
</shared-input-calendar>
<shared-input-calendar
name="Hora de llegada"
type="datetime-local"
[control]="arrivalDateTimeControl">
</shared-input-calendar>
</div>
<div class="actions">
<button (click)="onTogleDialogScale()" class="btn btn-cancel">Cancelar</button>
<button [disabled]="scalesForm.invalid" (click)="onSaveScale()" class="btn btn-accept">Aceptar</button>
</div>
</shared-dialog>
import { Component, Input, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { TableModel } from 'src/app/shared/interfaces/table-model.interface';
import { FlightScale } from '../../interfaces/flight-scale.interface';
import { DropdownElement } from 'src/app/shared/interfaces/dropdown-element-interface';
import { AirportsService } from 'src/app/agent/services/airports.service';
import { FlightTable } from '../../interfaces/flight-table.interface';
@Component({
selector: 'supervisor-scales-config',
templateUrl: './scales-config.component.html',
styleUrls: ['./scales-config.component.css']
})
export class ScalesConfigComponent implements OnInit {
constructor(private airportsService: AirportsService) { }
ngOnInit(): void {
this.getAllAirports();
}
public scaleModel: TableModel[] = [
{
name: 'id',
title: '#'
},
{
name: 'airportOrigin',
title: 'Origen'
},
{
name: 'airportDestination',
title: 'Destino'
},
{
name: 'departureDateTime',
title: 'Hora Inicio'
},
{
name: 'arrivalDateTime',
title: 'Hora Fin'
}
]
public openDialogScale: boolean = false;
@Input()
public scales: FlightScale[] = [];
public airports: DropdownElement[] = [];
public airportOriginIdControl: FormControl<number | null> = new FormControl(null, [Validators.required]);
public airportDestinationIdControl: FormControl<number | null> = new FormControl(null, [Validators.required]);
public departureDateTimeControl: FormControl<string | null> = new FormControl(null, [Validators.required]);
public arrivalDateTimeControl: FormControl<string | null> = new FormControl(null, [Validators.required]);
public scalesForm: FormGroup = new FormGroup({
airportOriginId: this.airportOriginIdControl,
airportDestinationId: this.airportDestinationIdControl,
departureDateTime: this.departureDateTimeControl,
arrivalDateTime: this.arrivalDateTimeControl,
}, {
validators: () => {
const airportOriginId = this.airportOriginIdControl.value;
const airportDestinationId = this.airportDestinationIdControl.value;
const departureDate = this.departureDateTimeControl.value;
const arrivalDate = this.arrivalDateTimeControl.value;
return this.scaleCrossValidation(airportOriginId, airportDestinationId, departureDate, arrivalDate);
}
});
scaleCrossValidation(airportOriginId: number | null, airportDestinationId: number | null,
departureDate: string | null, arrivalDate: string | null): { [key: string]: boolean } | null {
if (airportDestinationId == null) this.airportDestinationIdControl.setErrors({ required: true });
else if (airportOriginId === airportDestinationId) {
this.airportDestinationIdControl.setErrors({ airportEqual: true });
} else {
this.airportDestinationIdControl.setErrors(null);
}
if (departureDate == null) this.departureDateTimeControl.setErrors({ required: true });
else if (this.scales.filter(scale => {
const scaleDepartureDate = new Date(scale.departureDateTime);
const scaleArrivalDate = new Date(scale.arrivalDateTime);
const departureDateCompare = new Date(departureDate);
return (departureDateCompare >= scaleDepartureDate && departureDateCompare <= scaleDepartureDate) ||
(departureDateCompare >= scaleArrivalDate && departureDateCompare <= scaleArrivalDate)
}).length > 0) {
this.departureDateTimeControl.setErrors({ existCost: true });
} else this.departureDateTimeControl.setErrors(null);
if (arrivalDate == null) this.arrivalDateTimeControl.setErrors({ required: true });
else if (departureDate! >= arrivalDate) this.arrivalDateTimeControl.setErrors({ isInvalid: true });
else this.arrivalDateTimeControl.setErrors(null);
return null;
}
onTogleDialogScale(): void {
this.openDialogScale = !this.openDialogScale;
this.scalesForm.reset();
this.scales.length > 0 ? this.airportOriginIdControl.setValue(this.scales[this.scales.length - 1].airportDestinationId) : this.airportOriginIdControl.setValue(null);
}
getAllAirports(): void {
this.airportsService.getAll()
.subscribe(airports =>
{ this.airports = airports.map( airport => { return { value: airport.id, text: airport.name } } )});
}
getAirportById(id: number): string {
return this.airports.find(airport => airport.value == id)?.text || '';
}
onSaveScale(): void {
this.scalesForm.markAllAsTouched();
if (this.scalesForm.valid) {
const scale: FlightScale = {
id: this.scales.length + 1,
airportOrigin: this.getAirportById(this.airportOriginIdControl.value!),
airportOriginId: parseInt(this.scalesForm.value.airportOriginId),
airportDestination: this.getAirportById(this.airportDestinationIdControl.value!),
airportDestinationId: parseInt(this.scalesForm.value.airportDestinationId),
departureDateTime: this.scalesForm.value.departureDateTime,
arrivalDateTime: this.scalesForm.value.arrivalDateTime
}
this.scales.push(scale);
this.onTogleDialogScale();
}
}
}
export interface Agent { interface Agent {
id: number, id: number;
name: string, name: string;
lastname: string, lastname: string;
detail: string, details: string;
email: string,
password: string
} }
export const EMPTY_AGENT: Agent = { interface AgentExtended extends Agent {
id: 0, email: string;
password: string;
}
interface AgentSave {
name: string;
lastname: string;
details: string;
email: string;
password: string;
}
const EMPTY_AGENT_SAVE: AgentSave = {
name: '', name: '',
lastname: '', lastname: '',
detail: '', details: '',
email: '', email: '',
password: '' password: ''
} }
export { Agent, AgentExtended, AgentSave, EMPTY_AGENT_SAVE };
export interface Aircraft { export interface Aircraft {
id: number; id: number;
name: string; name: string;
model: string;
manufacturer: string; manufacturer: string;
model: string;
} }
export interface CostFlight { export interface FlightCost {
id: number; id: number;
dateStart: string; dateStart: string;
dateEnd: string; dateEnd: string;
aircraftType: string;
aircraftTypeId: number;
cost: number; cost: number;
} }
export interface FlightCostSave {
dateStart: string;
dateEnd: string;
cost: number;
}
import { FlightCostSave } from "./flight-save-cost.interface";
import { FlightScaleSave } from "./flight-scale-save.interface";
export interface FlightSave {
airlineId: number;
aircraftId: number;
departureDate: string;
arrivalDate: string;
legs: FlightScaleSave[];
costs: FlightCostSave[];
}
export interface FlightScaleSave {
airportOriginId: number;
airportDestinationId: number;
departureDateTime: string;
arrivalDateTime: string;
}
export interface ScaleFlight { export interface FlightScale {
id: number; id: number;
airportOrigin: string; airportOrigin: string;
airportOriginId: number; airportOriginId: number;
airportDestination: string; airportDestination: string;
airportDestinationId: number; airportDestinationId: number;
dateStart: string; departureDateTime: string;
dateEnd: string; arrivalDateTime: string;
} }
export interface FlightTable {
id: number;
airportOrigin: string;
airportDestination: string;
departureDate: string;
arrivalDate: string;
}
import { CostFlight } from "./cost-flight.interface"; import { FlightCost } from "./flight-cost.interface";
import { ScaleFlight } from "./scale.interface"; import { FlightScale } from "./flight-scale.interface";
export interface Flight { export interface Flight {
id: number; id: number;
airline: string; airline: string;
airlineId: number; airlineId: number;
aircraftType: string; aircraftId: number;
aircraftTypeId: number; aircradt: string;
airportOrigin: string; airportOrigin: string;
airportOriginId: number; airportOriginId: number;
airportDestination: string; airportDestination: string;
airportDestinationId: number; airportDestinationId: number;
dateStart: string; departureDate: string;
dateEnd: string; arrivalDate: string;
scales: ScaleFlight[]; flightType: string;
costs: CostFlight[]; price: number;
legs: FlightScale[];
costs: FlightCost[];
} }
...@@ -21,9 +21,9 @@ ...@@ -21,9 +21,9 @@
<shared-input-validator [formGroup]="agentForm" field="lastname" [getValidatorLength]="getAgentValidatorLenght"></shared-input-validator> <shared-input-validator [formGroup]="agentForm" field="lastname" [getValidatorLength]="getAgentValidatorLenght"></shared-input-validator>
</div> </div>
<div class="field field-detail"> <div class="field field-detail">
<label for="detail">Detalle *</label> <label for="details">Detalle *</label>
<input type="text" formControlName="detail" name="detail" id="detail"> <input type="text" formControlName="details" name="details" id="details">
<shared-input-validator [formGroup]="agentForm" field="detail" [getValidatorLength]="getAgentValidatorLenght"></shared-input-validator> <shared-input-validator [formGroup]="agentForm" field="details" [getValidatorLength]="getAgentValidatorLenght"></shared-input-validator>
</div> </div>
</div> </div>
</section> </section>
......
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms'; import { FormGroup } from '@angular/forms';
import { AgentsService } from '../../services/agent.service'; import { AgentsService } from '../../services/agent.service';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { AGENT_VALIDATORS, getAgentValidatorLenght } from '../../validators/agent.validator'; import { AGENT_VALIDATORS, getAgentValidatorLenght } from '../../validators/agent.validator';
import { Agent, EMPTY_AGENT } from '../../interfaces/agent.interface'; import { AgentSave, EMPTY_AGENT_SAVE } from '../../interfaces/agent.interface';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { SecurityService } from 'src/app/security/services/security.service';
@Component({ @Component({
selector: 'app-agent-add', selector: 'app-agent-add',
...@@ -16,7 +17,8 @@ export class AgentAddComponent implements OnInit { ...@@ -16,7 +17,8 @@ export class AgentAddComponent implements OnInit {
constructor( constructor(
private location: Location, private location: Location,
private activatedRouter: ActivatedRoute, private activatedRouter: ActivatedRoute,
private agentsService: AgentsService) {} private agentsService: AgentsService,
private securityService: SecurityService) {}
agentForm: FormGroup = AGENT_VALIDATORS; agentForm: FormGroup = AGENT_VALIDATORS;
agentId?: number; agentId?: number;
...@@ -27,14 +29,14 @@ export class AgentAddComponent implements OnInit { ...@@ -27,14 +29,14 @@ export class AgentAddComponent implements OnInit {
if (param['id']) { if (param['id']) {
this.agentsService.getById(param['id']).subscribe(agent => this.updateValues(agent)) this.agentsService.getById(param['id']).subscribe(agent => this.updateValues(agent))
this.agentId = param['id']; this.agentId = param['id'];
} else this.updateValues(EMPTY_AGENT); } else this.updateValues(EMPTY_AGENT_SAVE);
}); });
} }
updateValues(agent: Agent): void { updateValues(agent: AgentSave): void {
this.agentForm.get('name')?.setValue(agent.name || ''); this.agentForm.get('name')?.setValue(agent.name || '');
this.agentForm.get('lastname')?.setValue(agent.lastname || ''); this.agentForm.get('lastname')?.setValue(agent.lastname || '');
this.agentForm.get('detail')?.setValue(agent.detail || ''); this.agentForm.get('details')?.setValue(agent.details || '');
this.agentForm.get('email')?.setValue(agent.email || ''); this.agentForm.get('email')?.setValue(agent.email || '');
this.agentForm.get('password')?.setValue(agent.password || ''); this.agentForm.get('password')?.setValue(agent.password || '');
} }
...@@ -52,11 +54,11 @@ export class AgentAddComponent implements OnInit { ...@@ -52,11 +54,11 @@ export class AgentAddComponent implements OnInit {
this.location.back() this.location.back()
}); });
} else { } else {
this.agentsService.save(this.agentForm.value) this.securityService.signup({...this.agentForm.value, role: 'agent'})
.subscribe(() => { .subscribe(() => {
this.agentForm.reset(); this.agentForm.reset();
this.location.back() this.location.back()
}); });
} }
} }
} }
...@@ -27,7 +27,7 @@ export class AgentsComponent implements OnInit { ...@@ -27,7 +27,7 @@ export class AgentsComponent implements OnInit {
title: "Apellidos" title: "Apellidos"
}, },
{ {
name: 'detail', name: 'details',
title: "Detalles" title: "Detalles"
} }
]; ];
......
...@@ -16,17 +16,6 @@ ...@@ -16,17 +16,6 @@
gap: 20px; gap: 20px;
} }
.btn-add {
border: 1px solid #e0e0e0;
border-radius: 50%;
width: 42px;
height: 42px;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 0 5px 0 #0000001f;
}
.btn-save { .btn-save {
background-color: #1ab394; background-color: #1ab394;
border: 1px solid #1ab394; border: 1px solid #1ab394;
...@@ -37,35 +26,3 @@ ...@@ -37,35 +26,3 @@
/* Configuracion de escalas */ /* Configuracion de escalas */
.fields {
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: 16px;
}
.actions {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 10px;
margin-top: 30px;
border-top: 1px solid #e0e0e0;
}
.btn-cancel {
border: 1px solid #ccc;
color: #ccc;
font-size: 12px;
}
.btn-accept {
border: 1px solid #1ab394;
background-color: #1ab394;
color: white;
font-size: 12px;
}
.flight__type, .flight__optional{
grid-column: 1 / 3;
}
...@@ -4,95 +4,34 @@ ...@@ -4,95 +4,34 @@
message="Este gestor permite realizar la configuración de vuelos" message="Este gestor permite realizar la configuración de vuelos"
icon="bi-airplane" icon="bi-airplane"
[btnBack]="true"> [btnBack]="true">
<!-- General Information -->
<section class="section"> <section class="section">
<h4 class="section__title">Información general</h4> <h4 class="section__title">Información general</h4>
<div class="row gap-2"> <supervisor-base-config
<shared-input-selector [airlineControl]="airlineControl"
class="col-12" [aircraftControl]="aircraftControl"
name="Aerolinea" [departureDateControl]="departureDateControl"
(onSelect)="onSelectAirline($event)" [arrivalDateControl]="arrivalDateControl">
[value]="airlineValue" </supervisor-base-config>
[tableModel]="airlineModel"
[tableData]="airlines">
</shared-input-selector>
<shared-input-dropdown
name="Tipo de avion"
class="col-12"
[control]="aircraftTypeIdControl"
[data]="aircrafts">
</shared-input-dropdown>
</div>
</section> </section>
<section class="section"> <section class="section">
<h4 class="section__title">Configuración de vuelo</h4> <h4 class="section__title mb-4">Configuración de vuelo</h4>
<shared-panel-menu <shared-panel-menu
[panelItems]="panelMenu" [panelItems]="panelMenu"
(onChangeItemActive)="onchangeItemActive($event)"> (onChangeItemActive)="onchangeItemActive($event)">
<div [ngSwitch]="panelMenuActive.name"> <div [ngSwitch]="panelMenuActive.name">
<div *ngSwitchCase="'scales'"> <supervisor-scales-config
*ngSwitchCase="'scales'"
<shared-table-custom [scales]="scales">
[tableModel]="scaleModel" </supervisor-scales-config>
[tableData]="scales"> <supervisor-costs-config
<div class="more-actions"> *ngSwitchCase="'costs'"
<button (click)="onTogleDialogScale()" class="btn btn-add"> [costs]="costs">
<i class="bi bi-plus"></i> </supervisor-costs-config>
</button>
</div>
</shared-table-custom>
<shared-dialog
title="Configurar escala"
[isActivated]="openDialogScale"
(onCloseDialog)="onTogleDialogScale()">
<div class="fields">
<shared-input-dropdown name="Aeropuero de partida" [control]="airportIdOriginControl" [data]="airports"></shared-input-dropdown>
<shared-input-dropdown name="Aeropuero de llegada" [control]="airportIdDestinationControl" [data]="airports"></shared-input-dropdown>
<shared-input-calendar name="Fecha de partida" type="datetime-local" [control]="dateStartControl"></shared-input-calendar>
<shared-input-calendar name="Fecha de llegada" type="datetime-local" [control]="dateEndControl"></shared-input-calendar>
</div>
<div class="actions">
<button (click)="onTogleDialogScale()" class="btn btn-cancel">Cancelar</button>
<button [disabled]="scalesForm.invalid" (click)="onSaveScale()" class="btn btn-accept">Aceptar</button>
</div>
</shared-dialog>
</div>
<div *ngSwitchCase="'costs'">
<shared-table-custom
[tableModel]="costModel"
[tableData]="costs">
<div class="more-actions">
<button (click)="onTogleDialogCost()" class="btn btn-add">
<i class="bi bi-plus"></i>
</button>
</div>
</shared-table-custom>
<shared-dialog
title="Configurar costos"
(onCloseDialog)="onTogleDialogCost()"
[isActivated]="openDialogCost">
<div class="fields">
<shared-input-calendar name="Fecha de inicio" type="date" [control]="dateStartCostControl"></shared-input-calendar>
<shared-input-calendar name="Fecha de fin" type="date" [control]="dateEndCostControl"></shared-input-calendar>
<shared-input-dropdown name="Tipo de aeronave" [data]="aircrafts" [control]="aircraftIdControl"></shared-input-dropdown>
<shared-input-text label="Costo *" type="number" [control]="costControl"></shared-input-text>
</div>
<div class="actions">
<button (click)="onTogleDialogCost()" class="btn btn-cancel">Cancelar</button>
<button [disabled]="costsForm.invalid" (click)="onSaveCost()" class="btn btn-accept">Aceptar</button>
</div>
</shared-dialog>
</div>
</div> </div>
</shared-panel-menu> </shared-panel-menu>
</section> </section>
<div class="actions d-flex justify-content-end"> <div class="actions d-flex justify-content-end">
<button [disabled]="isInvalidFlightConfiguration()" (click)="onSaveFlightConfig()" class="btn btn-save"> <button [disabled]="isInvalidForm()" (click)="onSaveFlightConfig()" class="btn btn-save">
<i class="bi bi-save me-1"></i> <i class="bi bi-save me-1"></i>
<span>Guardar</span> <span>Guardar</span>
</button> </button>
......
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { PanelItem } from '../../interfaces/panel-item.interface'; import { PanelItem } from '../../interfaces/panel-item.interface';
import { TableModel } from 'src/app/shared/interfaces/table-model.interface'; import { FormControl, FormGroup, Validators } from '@angular/forms';
import { AirportsService } from 'src/app/agent/services/airports.service'; import { FlightScale } from '../../interfaces/flight-scale.interface';
import { Airline } from '../../interfaces/airline.interface'; import { FlightCost } from '../../interfaces/flight-cost.interface';
import { AirlineService } from '../../services/airline.service';
import { ScaleFlight } from '../../interfaces/scale.interface';
import { CostFlight } from '../../interfaces/cost-flight.interface';
import { FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms';
import { DropdownElement } from 'src/app/shared/interfaces/dropdown-element-interface';
import { AircraftService } from '../../services/aircraft.service';
import { FlightService } from '../../services/flight.service';
import { Flight } from '../../interfaces/flight.interface'; import { Flight } from '../../interfaces/flight.interface';
import { ActivatedRoute } from '@angular/router'; import { FlightSave } from '../../interfaces/flight-save.interface';
import { FlightScaleSave } from '../../interfaces/flight-scale-save.interface';
import { FlightCostSave } from '../../interfaces/flight-save-cost.interface';
import { FlightService } from '../../services/flight.service';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { ActivatedRoute } from '@angular/router';
@Component({ @Component({
selector: 'app-flight-add', selector: 'app-flight-add',
...@@ -21,66 +18,30 @@ import { Location } from '@angular/common'; ...@@ -21,66 +18,30 @@ import { Location } from '@angular/common';
}) })
export class FlightAddComponent implements OnInit { export class FlightAddComponent implements OnInit {
public airlineModel: TableModel[] = [ constructor(private flightService: FlightService,
{ private location: Location,
name: 'id', private activatedRoute: ActivatedRoute) { }
title: '#'
},
{
name: 'name',
title: 'Nombre'
},
{
name: 'code',
title: 'Código'
}
]
public scaleModel: TableModel[] = [ ngOnInit(): void {
{ this.activatedRoute.params
name: 'id', .subscribe(params => {
title: '#' if (params['id']) {
}, this.flightService.getById(params['id'])
{ .subscribe(flight => {
name: 'airportOrigin', console.log(flight);
title: 'Origen' this.flightBaseConfig.patchValue({
}, airlineId: flight.airlineId,
{ aircraftId: flight.aircraftId,
name: 'airportDestination', departureDate: flight.departureDate,
title: 'Destino' arrivalDate: flight.arrivalDate
}, });
{ this.scales = flight.legs;
name: 'dateStart', this.costs = flight.costs;
title: 'Fecha Inicio' this.isUpdated = true;
}, });
{ }
name: 'dateEnd', })
title: 'Fecha Fin' }
}
]
public costModel: TableModel[] = [
{
name: 'id',
title: '#'
},
{
name: 'dateStart',
title: 'Fecha Inicio'
},
{
name: 'dateEnd',
title: 'Fecha Fin'
},
{
name: 'aircraftType',
title: 'Tipo de Avión'
},
{
name: 'cost',
title: 'Costo'
}
]
public panelMenu: PanelItem[] = [ public panelMenu: PanelItem[] = [
{ {
...@@ -97,281 +58,69 @@ export class FlightAddComponent implements OnInit { ...@@ -97,281 +58,69 @@ export class FlightAddComponent implements OnInit {
} }
]; ];
public panelMenuActive: PanelItem = this.panelMenu[0]; public airlineControl: FormControl<number | null> = new FormControl(null, [Validators.required]);
public aircraftControl: FormControl<number | null> = new FormControl(null, [Validators.required]);
// Info public departureDateControl: FormControl<string | null> = new FormControl(null, [Validators.required]);
public scales: ScaleFlight[] = []; public arrivalDateControl: FormControl<string | null> = new FormControl(null, [Validators.required]);
public costs: CostFlight[] = [];
public openDialogScale: boolean = false;
public openDialogCost: boolean = false;
public airlines: Airline[] = [];
public airports: DropdownElement[] = [];
public aircrafts: DropdownElement[] = [];
public airlineValue: string = '';
public airlineIdControl: FormControl = new FormControl<number | null>(null, [Validators.required]);
public aircraftTypeIdControl: FormControl = new FormControl<number | null>(null, [Validators.required]);
public flightBaseConfig: FormGroup = new FormGroup({ public flightBaseConfig: FormGroup = new FormGroup({
airlineId: this.airlineIdControl, airlineId: this.airlineControl,
aircraftTypeId: this.aircraftTypeIdControl, aircraftId: this.aircraftControl,
}); departureDate: this.departureDateControl,
arrivalDate: this.arrivalDateControl
public airportIdOriginControl: FormControl = new FormControl<number | null>(null, [Validators.required]);
public airportIdDestinationControl: FormControl = new FormControl<number | null>(null, [Validators.required]);
public dateStartControl: FormControl = new FormControl<string | null>(null, [Validators.required]);
public dateEndControl: FormControl = new FormControl<string | null>(null, [Validators.required]);
public scalesForm: FormGroup = new FormGroup({
airportIdOrigin: this.airportIdOriginControl,
airportIdDestination: this.airportIdDestinationControl,
dateStart: this.dateStartControl,
dateEnd: this.dateEndControl,
});
public dateStartCostControl: FormControl = new FormControl<string | null>(null, [Validators.required]);
public dateEndCostControl: FormControl = new FormControl<string | null>(null, [Validators.required]);
public costControl: FormControl = new FormControl<number | null>(null, [Validators.required]);
public aircraftIdControl: FormControl = new FormControl<number | null>(null, [Validators.required]);
public costsForm: FormGroup = new FormGroup({
dateStart: this.dateStartCostControl,
dateEnd: this.dateEndCostControl,
cost: this.costControl,
aircraftId: this.aircraftIdControl,
}); });
constructor(private airportsService: AirportsService, public scales: FlightScale[] = [];
private airlinesService: AirlineService, public costs: FlightCost[] = [];
private aircraftService: AircraftService,
private flightService: FlightService,
private activatedRoute: ActivatedRoute,
private location: Location) {
this.addCustomValidatorsInScaleForm();
this.addCustomValidatorsInCostForm();
}
ngOnInit(): void {
this.getAllData();
this.activatedRoute.params
.subscribe(params => {
const id = params['id'];
if (id) {
this.flightService.getById(id)
.subscribe(flight => {
this.airlineValue = flight.airline;
this.airlineIdControl.setValue(flight.airlineId);
this.aircraftTypeIdControl.setValue(flight.aircraftTypeId);
this.scales = flight.scales;
this.costs = flight.costs;
});
}
});
}
getAllData(): void {
this.airlinesService.getAll()
.subscribe(airlines => this.airlines = airlines);
this.airportsService.getAll() public isUpdated: boolean = false;
.subscribe(airports => {
const airportsDropdown: DropdownElement[] = [];
airports.map(airport => {
airportsDropdown.push({
text: airport.name,
value: airport.id.toString()
});
});
this.airports = airportsDropdown;
});
this.aircraftService.getAll() public panelMenuActive: PanelItem = this.panelMenu[0];
.subscribe(response => {
const aircrafts: DropdownElement[] = [];
response.map(aircraft => {
aircrafts.push({
text: aircraft.name,
value: aircraft.id.toString()
});
});
this.aircrafts = aircrafts;
})
}
onTogleDialogScale(): void {
this.openDialogScale = !this.openDialogScale;
this.scalesForm.reset();
}
onTogleDialogCost(): void {
this.openDialogCost = !this.openDialogCost;
this.costsForm.reset();
}
onSelectAirline(airline: Airline): void {
this.airlineValue = airline.name;
this.airlineIdControl.setValue(airline.id);
}
onchangeItemActive(item: PanelItem): void { onchangeItemActive(item: PanelItem): void {
this.panelMenuActive = item; this.panelMenuActive = item;
} }
// Getters isInvalidForm(): boolean {
return this.flightBaseConfig.invalid || this.scales.length === 0 || this.costs.length === 0 || this.isUpdated;
isInvalidFlightConfiguration(): boolean {
return this.flightBaseConfig.invalid || this.scales.length == 0 || this.costs.length == 0;
}
// Custom Validators
addCustomValidatorsInScaleForm(): void {
this.dateEndControl.addValidators(this.dateValidator());
this.dateStartControl.addValidators(this.dateValidator());
this.airportIdOriginControl.addValidators(this.airportValidator());
this.airportIdDestinationControl.addValidators(this.airportValidator());
this.dateStartControl.valueChanges.subscribe(() => {
this.dateEndControl.updateValueAndValidity();
});
this.dateEndControl.valueChanges.subscribe(() => {
this.dateStartControl.updateValueAndValidity();
});
this.airportIdOriginControl.valueChanges.subscribe(() => {
this.airportIdDestinationControl.updateValueAndValidity();
});
this.airportIdDestinationControl.valueChanges.subscribe(() => {
this.airportIdOriginControl.updateValueAndValidity();
});
}
addCustomValidatorsInCostForm(): void {
this.dateEndCostControl.addValidators(this.dateCostValidator());
this.dateStartCostControl.addValidators(this.dateCostValidator());
this.dateStartCostControl.valueChanges.subscribe(() => {
this.dateEndCostControl.updateValueAndValidity();
});
this.dateEndCostControl.valueChanges.subscribe(() => {
this.dateStartCostControl.updateValueAndValidity();
});
}
dateValidator(): ValidatorFn {
return () => {
const dateStart = this.dateStartControl.value;
const dateEnd = this.dateEndControl.value;
if(!dateStart || !dateEnd) return { isValid: false };
if(dateStart === dateEnd) return { isValid: false };
if (new Date(dateStart) > new Date(dateEnd)) return { isValid: false };
return null;
};
}
airportValidator(): ValidatorFn {
return () => {
const airportOrigin = this.airportIdOriginControl.value;
const airportDestination = this.airportIdDestinationControl.value;
if(!airportOrigin || !airportDestination) return { isValid: false };
if(airportOrigin === airportDestination) return { isValid:false };
return null;
};
} }
dateCostValidator(): ValidatorFn {
return () => {
const dateStart = this.dateStartCostControl.value;
const dateEnd = this.dateEndCostControl.value;
if(!dateStart || !dateEnd) return { isValid: false };
if(dateStart === dateEnd) return { isValid: false };
if (new Date(dateStart) > new Date(dateEnd)) return { isValid: false };
return null;
};
}
// Function OnSave
onSaveFlightConfig(): void { onSaveFlightConfig(): void {
this.flightBaseConfig.markAllAsTouched();
if (this.flightBaseConfig.valid && this.scales.length > 0 && this.costs.length > 0) { if (this.flightBaseConfig.valid && this.scales.length > 0 && this.costs.length > 0) {
const flightConfig: Flight = {
id: 0,
airline: this.airlines.find(airline => airline.id === this.airlineIdControl.value)?.name || '',
airlineId: this.airlineIdControl.value,
airportOrigin: this.scales[0].airportOrigin,
airportOriginId: this.scales[0].airportOriginId,
airportDestination: this.scales[this.scales.length - 1].airportDestination,
airportDestinationId: this.scales[this.scales.length - 1].airportDestinationId,
dateStart: this.scales[0].dateStart,
dateEnd: this.scales[this.scales.length - 1].dateEnd,
aircraftType: this.aircrafts.find(aircraft => aircraft.value === this.aircraftTypeIdControl.value)?.text || '',
aircraftTypeId: Number.parseInt(this.aircraftTypeIdControl.value),
scales: this.scales,
costs: this.costs
}
this.flightService.save(flightConfig)
.subscribe(response => {
console.log(response);
});
this.flightBaseConfig.reset(); const legs: FlightScaleSave[] = this.scales.map(scale => {
this.scales = []; return {
this.costs = []; airportOriginId: scale.airportOriginId,
this.location.back(); airportDestinationId: scale.airportDestinationId,
} departureDateTime: scale.departureDateTime,
} arrivalDateTime: scale.arrivalDateTime
}
});
onSaveScale(): void { const costs: FlightCostSave[] = this.costs.map(cost => {
this.scalesForm.markAllAsTouched(); return {
if (this.scalesForm.valid) { dateStart: cost.dateStart,
dateEnd: cost.dateEnd,
cost: cost.cost
}
});
const scale: ScaleFlight = { const flight: FlightSave = {
id: this.scales.length + 1, airlineId: parseInt(this.flightBaseConfig.value.airlineId),
airportOrigin: this.airports.find(airport => airport.value === this.airportIdOriginControl.value)?.text || '', aircraftId: parseInt(this.flightBaseConfig.value.aircraftId),
airportOriginId: Number.parseInt(this.airports.find(airport => airport.value === this.airportIdOriginControl.value)?.value || ''), departureDate: this.flightBaseConfig.value.departureDate,
airportDestination: this.airports.find(airport => airport.value === this.airportIdDestinationControl.value)?.text || '', arrivalDate: this.flightBaseConfig.value.arrivalDate,
airportDestinationId: Number.parseInt(this.airportIdDestinationControl.value) || 0, legs,
dateStart: this.dateStartControl.value, costs
dateEnd: this.dateEndControl.value,
} }
console.log(scale);
this.scales.push(scale); this.flightService.save(flight)
this.onTogleDialogScale(); .subscribe((_: Flight) => {
this.scalesForm.reset(); this.flightBaseConfig.reset();
} this.scales = [];
} this.costs = [];
this.location.back();
onSaveCost(): void { });
this.costsForm.markAllAsTouched();
if (this.costsForm.valid) {
const cost: CostFlight = {
id: this.costs.length + 1,
dateStart: this.dateStartCostControl.value,
dateEnd: this.dateEndCostControl.value,
aircraftType: this.aircrafts.find(aircraft => aircraft.value === this.aircraftIdControl.value)?.text || '',
aircraftTypeId: Number.parseInt(this.aircraftIdControl.value) || 0,
cost: this.costControl.value
}
console.log(cost);
this.costs.push(cost);
this.onTogleDialogCost();
this.costsForm.reset();
} }
} }
} }
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ResultDelete } from 'src/app/shared/interfaces/result-delete.interface'; import { ResultDelete } from 'src/app/shared/interfaces/result-delete.interface';
import { TableModel } from 'src/app/shared/interfaces/table-model.interface'; import { TableModel } from 'src/app/shared/interfaces/table-model.interface';
import { Flight } from '../../interfaces/flight.interface';
import { FlightService } from '../../services/flight.service'; import { FlightService } from '../../services/flight.service';
import { FlightTable } from '../../interfaces/flight-table.interface';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({ @Component({
selector: 'app-flight-config', selector: 'app-flight-config',
...@@ -11,7 +12,13 @@ import { FlightService } from '../../services/flight.service'; ...@@ -11,7 +12,13 @@ import { FlightService } from '../../services/flight.service';
}) })
export class FlightConfigComponent implements OnInit { export class FlightConfigComponent implements OnInit {
tableData: Flight[] = []; constructor(private flightService: FlightService) {}
ngOnInit(): void {
this.getFlights();
}
tableData: FlightTable[] = [];
tableModel: TableModel[] = [ tableModel: TableModel[] = [
{ {
name: 'id', name: 'id',
...@@ -26,21 +33,15 @@ export class FlightConfigComponent implements OnInit { ...@@ -26,21 +33,15 @@ export class FlightConfigComponent implements OnInit {
title: 'Aeropuerto destino', title: 'Aeropuerto destino',
}, },
{ {
name: 'dateStart', name: 'departureDate',
title: 'Fecha de partida' title: 'Fecha de partida'
}, },
{ {
name: 'dateEnd', name: 'arrivalDate',
title: 'Fecha de llegada' title: 'Fecha de llegada'
} }
]; ];
constructor(private flightService: FlightService) {}
ngOnInit(): void {
this.getFlights();
}
getFlights(): void { getFlights(): void {
this.flightService.getAll() this.flightService.getAll()
.subscribe(flights => { .subscribe(flights => {
...@@ -49,6 +50,11 @@ export class FlightConfigComponent implements OnInit { ...@@ -49,6 +50,11 @@ export class FlightConfigComponent implements OnInit {
} }
onDeleteAgent(result: ResultDelete): void { onDeleteAgent(result: ResultDelete): void {
if (result.result) {
this.flightService.delete(result.id)
.subscribe(() => {
this.tableData = this.tableData.filter(agent => agent.id !== result.id);
});
}
} }
} }
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { Agent } from '../interfaces/agent.interface'; import { Agent, AgentExtended, AgentSave } from '../interfaces/agent.interface';
import { headers } from 'src/app/shared/utils/header.util';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class AgentsService { export class AgentsService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
private BASE_URL: string = 'http://localhost:3000/agents'; private BASE_URL: string = 'http://localhost:8085/api/v1/agents';
getAll(): Observable<Agent[]> { getAll(): Observable<Agent[]> {
return this.http.get<Agent[]>(this.BASE_URL); console.log(headers)
return this.http.get<Agent[]>(this.BASE_URL, { headers });
} }
getById(id: number): Observable<Agent> { getById(id: number): Observable<AgentExtended> {
return this.http.get<Agent>(`${this.BASE_URL}/${id}`); return this.http.get<AgentExtended>(`${this.BASE_URL}/${id}`, { headers });
} }
save(agent: Agent): Observable<Agent> { edit(id: number, agent: AgentSave): Observable<AgentExtended> {
return this.http.post<Agent>(this.BASE_URL, agent); return this.http.put<AgentExtended>(`${this.BASE_URL}/${id}`, agent, { headers});
} }
edit(id: number, agent: Agent): Observable<Agent> { delete(id: number): Observable<AgentExtended> {
return this.http.put<Agent>(`${this.BASE_URL}/${id}`, agent); return this.http.delete<AgentExtended>(`${this.BASE_URL}/${id}`, { headers });
}
delete(id: number): Observable<Agent> {
return this.http.delete<Agent>(`${this.BASE_URL}/${id}`);
} }
} }
...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core'; ...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { Aircraft } from '../interfaces/aircraft.interface'; import { Aircraft } from '../interfaces/aircraft.interface';
import { headers } from 'src/app/shared/utils/header.util';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class AircraftService { export class AircraftService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
URL_BASE: string = 'http://localhost:3000/aircrafts'; URL_BASE: string = 'http://localhost:8085/api/v1/aircrafts';
getAll(): Observable<Aircraft[]> { getAll(): Observable<Aircraft[]> {
return this.http.get<Aircraft[]>(this.URL_BASE); return this.http.get<Aircraft[]>(this.URL_BASE, { headers });
} }
} }
...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core'; ...@@ -2,14 +2,15 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { Airline } from '../interfaces/airline.interface'; import { Airline } from '../interfaces/airline.interface';
import { headers } from 'src/app/shared/utils/header.util';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class AirlineService { export class AirlineService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
BASE_URL = 'http://localhost:3000'; BASE_URL = 'http://localhost:8085/api/v1/airlines';
getAll(): Observable<Airline[]> { getAll(): Observable<Airline[]> {
return this.http.get<Airline[]>(`${this.BASE_URL}/airlines`); return this.http.get<Airline[]>(this.BASE_URL, { headers });
} }
} }
...@@ -2,34 +2,38 @@ import { Injectable } from '@angular/core'; ...@@ -2,34 +2,38 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { Flight } from '../interfaces/flight.interface'; import { Flight } from '../interfaces/flight.interface';
import { FlightTable } from '../interfaces/flight-table.interface';
import { FlightSave } from '../interfaces/flight-save.interface';
import { headers } from 'src/app/shared/utils/header.util';
@Injectable({providedIn: 'root'}) @Injectable({providedIn: 'root'})
export class FlightService { export class FlightService {
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
URL_BASE: string = 'http://localhost:3000/flights'; URL_BASE: string = 'http://localhost:8085/api/v1/flights';
getAll(): Observable<Flight[]> { getAll(): Observable<FlightTable[]> {
return this.http.get<Flight[]>(this.URL_BASE); return this.http.get<FlightTable[]>(this.URL_BASE, { headers});
} }
searchFlight(origin: string, destination: string, dateStart: string): Observable<Flight[]> { searchFlight(airportOriginId: number,
return this.http.get<Flight[]>(`${this.URL_BASE}?airportOrigin_like=${origin}&airportDestination_like=${destination}&dateStart_like=${dateStart}`); airportDestinationId: number, dateStart: string): Observable<Flight[]> {
return this.http.get<Flight[]>(`${this.URL_BASE}/search?airportOriginId=${airportOriginId}&airportDestinationId=${airportDestinationId}&startDate=${dateStart}`, { headers });
} }
getById(id: number): Observable<Flight> { getById(id: number): Observable<Flight> {
return this.http.get<Flight>(`${this.URL_BASE}/${id}`); return this.http.get<Flight>(`${this.URL_BASE}/${id}`, { headers });
} }
save(flight: Flight): Observable<Flight> { save(flight: FlightSave): Observable<Flight> {
return this.http.post<Flight>(this.URL_BASE, flight); return this.http.post<Flight>(this.URL_BASE, flight, { headers });
} }
update(flight: Flight): Observable<Flight> { update(flight: Flight): Observable<Flight> {
return this.http.put<Flight>(`${this.URL_BASE}/${flight.id}`, flight); return this.http.put<Flight>(`${this.URL_BASE}/${flight.id}`, flight, { headers });
} }
delete(id: number): Observable<Flight> { delete(id: number): Observable<Flight> {
return this.http.delete<Flight>(`${this.URL_BASE}/${id}`); return this.http.delete<Flight>(`${this.URL_BASE}/${id}`, { headers });
} }
} }
...@@ -9,6 +9,9 @@ import { AgentAddComponent } from './pages/agent-add/agent-add.component'; ...@@ -9,6 +9,9 @@ import { AgentAddComponent } from './pages/agent-add/agent-add.component';
import { HttpClientModule } from '@angular/common/http'; import { HttpClientModule } from '@angular/common/http';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { FlightAddComponent } from './pages/flight-add/flight-add.component'; import { FlightAddComponent } from './pages/flight-add/flight-add.component';
import { ScalesConfigComponent } from './components/scales-config/scales-config.component';
import { CostsConfigComponent } from './components/costs-config/costs-config.component';
import { BaseConfigComponent } from './components/base-config/base-config.component';
...@@ -18,7 +21,10 @@ import { FlightAddComponent } from './pages/flight-add/flight-add.component'; ...@@ -18,7 +21,10 @@ import { FlightAddComponent } from './pages/flight-add/flight-add.component';
AgentsComponent, AgentsComponent,
HomePageComponent, HomePageComponent,
AgentAddComponent, AgentAddComponent,
FlightAddComponent FlightAddComponent,
ScalesConfigComponent,
CostsConfigComponent,
BaseConfigComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
......
...@@ -10,7 +10,7 @@ const passwordLenght = { min: 3, max: 45 }; ...@@ -10,7 +10,7 @@ const passwordLenght = { min: 3, max: 45 };
export const AGENT_VALIDATORS = new FormGroup( { export const AGENT_VALIDATORS = new FormGroup( {
name: new FormControl('', [Validators.required, Validators.minLength(nameLenght.min), Validators.maxLength(nameLenght.max)]), name: new FormControl('', [Validators.required, Validators.minLength(nameLenght.min), Validators.maxLength(nameLenght.max)]),
lastname: new FormControl('', [Validators.required, Validators.minLength(lastnameLenght.min), Validators.maxLength(lastnameLenght.max)]), lastname: new FormControl('', [Validators.required, Validators.minLength(lastnameLenght.min), Validators.maxLength(lastnameLenght.max)]),
detail: new FormControl('', [Validators.maxLength(detailLenght.max)]), details: new FormControl('', [Validators.maxLength(detailLenght.max)]),
email: new FormControl('', [Validators.required, Validators.minLength(emailLenght.min), Validators.maxLength(emailLenght.max)]), email: new FormControl('', [Validators.required, Validators.minLength(emailLenght.min), Validators.maxLength(emailLenght.max)]),
password: new FormControl('', [Validators.required, Validators.minLength(passwordLenght.min), Validators.maxLength(passwordLenght.max)]) password: new FormControl('', [Validators.required, Validators.minLength(passwordLenght.min), Validators.maxLength(passwordLenght.max)])
}); });
...@@ -21,7 +21,7 @@ export const getAgentValidatorLenght = (field: string) => { ...@@ -21,7 +21,7 @@ export const getAgentValidatorLenght = (field: string) => {
return nameLenght; return nameLenght;
case 'lastname': case 'lastname':
return lastnameLenght; return lastnameLenght;
case 'detail': case 'details':
return detailLenght; return detailLenght;
case 'email': case 'email':
return emailLenght; return emailLenght;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment