From 6c340b4229c8a44d118fffa0428caf7f6b87b7f8 Mon Sep 17 00:00:00 2001 From: Ryan Prather Date: Tue, 31 Dec 2024 23:01:37 +0000 Subject: [PATCH] first draft of case addresses and itineraries --- src/Controller/CaseController.php | 183 ++++++++++++++++- src/Controller/ItineraryController.php | 145 +++++++++++++ src/Entity/CaseItinerary.php | 194 ++++++++++++++++++ src/Entity/CaseLocation.php | 55 +++++ src/Entity/Location.php | 140 +++++++++++++ src/Libs/Libs.php | 21 +- src/Libs/Route.php | 47 +++++ src/Repository/CaseItineraryRepository.php | 43 ++++ src/Repository/CaseLocationRepository.php | 57 +++++ src/Repository/LocationRepository.php | 74 +++++++ .../addresses/add-case-address.html.twig | 76 +++++++ .../addresses/edit-case-address.html.twig | 76 +++++++ .../addresses/list-case-addresses.html.twig | 149 ++++++++++++++ .../internal/cases/itinerary/map.html.twig | 20 ++ 14 files changed, 1272 insertions(+), 8 deletions(-) create mode 100644 src/Controller/ItineraryController.php create mode 100644 src/Entity/CaseItinerary.php create mode 100644 src/Entity/CaseLocation.php create mode 100644 src/Entity/Location.php create mode 100644 src/Libs/Route.php create mode 100644 src/Repository/CaseItineraryRepository.php create mode 100644 src/Repository/CaseLocationRepository.php create mode 100644 src/Repository/LocationRepository.php create mode 100644 templates/internal/cases/addresses/add-case-address.html.twig create mode 100644 templates/internal/cases/addresses/edit-case-address.html.twig create mode 100644 templates/internal/cases/addresses/list-case-addresses.html.twig create mode 100644 templates/internal/cases/itinerary/map.html.twig diff --git a/src/Controller/CaseController.php b/src/Controller/CaseController.php index b48b171..7f39bf6 100644 --- a/src/Controller/CaseController.php +++ b/src/Controller/CaseController.php @@ -2,15 +2,19 @@ namespace App\Controller; +use App\Entity\CaseLocation; +use App\Entity\Location; use App\Entity\MemberCase; use App\Entity\Messages; use App\Entity\ReferralSource; use App\Entity\User; use App\Entity\UserCase; use App\Factory\MessageFactory; +use App\Form\LocationFormType; use App\Form\MemberCaseFormType; use App\Form\UserCaseFormType; use App\Libs\Breadcrumb; +use App\Libs\Libs; use App\Libs\NavList; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -39,10 +43,11 @@ class CaseController extends AbstractController } #[Route('/my-cases', name: 'app_my_cases')] - public function myCases(#[CurrentUser()] User $user): Response + public function myCases(#[CurrentUser()] User $user, Request $request): Response { $this->navLinks['my_cases'] = NavList::PRESENT_LINK; $this->navLinks['case_list'] = 'nav-link text-dark'; + $ucs = $this->entityManager->getRepository(UserCase::class)->findBy(['user' => $user]); $this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user); $this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user); @@ -59,7 +64,11 @@ class CaseController extends AbstractController $this->navLinks, [ 'breadcrumbs' => [ - new Breadcrumb($this->generateUrl('app_my_cases'), 'List Cases') + ( + strpos($request->server->get('HTTP_REFERER'), 'list-cases') !== false + ? new Breadcrumb($this->generateUrl('app_list_cases'), 'List Cases') + : new Breadcrumb($this->generateUrl('app_my_cases'), 'My Cases') + ), ], 'notifications' => $this->msgs, 'cases' => $cases, @@ -276,6 +285,176 @@ class CaseController extends AbstractController return new Response(); } + #[Route('/addresses/list', name: 'app_list_case_addresses')] + public function listCaseAddresses(Request $request, #[CurrentUser()] User $user): Response + { + $this->navLinks['case_itinerary'] = NavList::PRESENT_LINK; + $this->navLinks['case_list'] = 'nav-link text-dark'; + + $addresses = $this->entityManager->getRepository(Location::class)->getUserLocations($user); + $this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user); + $this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user); + + $ucs = $this->entityManager->getRepository(UserCase::class)->findBy(['user' => $user]); + $cases = []; + foreach ($ucs as $uc) { + /** @var UserCase $uc */ + $cases[] = $uc->getMemberCase(); + } + + return $this->render( + 'internal/cases/addresses/list-case-addresses.html.twig', + array_merge( + $this->navLinks, + [ + 'title' => 'List Case Addresses', + 'breadcrumbs' => [ + new Breadcrumb($this->generateUrl('app_my_cases'), 'My Cases'), + new Breadcrumb($this->generateUrl('app_list_case_addresses'), 'List Case Addresses') + ], + 'notifications' => $this->msgs, + 'notificationCount' => $this->notificationCount, + 'addresses' => $addresses, + 'cases' => $cases, + ] + ) + ); + } + + #[Route('/addresses/add', name: 'app_case_add_address')] + public function addCaseAddress(Request $request, #[CurrentUser()] User $user): Response + { + $this->navLinks['case_itinerary'] = NavList::PRESENT_LINK; + $this->navLinks['case_list'] = 'nav-link text-dark'; + + $this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user); + $this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user); + $ucs = $this->entityManager->getRepository(UserCase::class)->findBy(['user' => $user]); + + $cases = []; + foreach ($ucs as $uc) { + /** @var UserCase $uc */ + $cases[] = $uc->getMemberCase(); + } + + $address = new Location(); + $form = $this->createForm(LocationFormType::class, $address); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + /** @var Location $address */ + $address = $form->getData(); + + foreach ($request->get('cases') as $caseId) { + $case = $this->entityManager->getRepository(MemberCase::class)->find($caseId); + + $cl = new CaseLocation(); + $cl->setMemberCase($case) + ->setLocation($address); + + $this->entityManager->persist($cl); + } + + list($lat, $lon) = Libs::getLatLonFromGeoapify((string) $address); + $address->setLat($lat) + ->setLon($lon); + + //dd($address); + $this->entityManager->persist($address); + $this->entityManager->flush(); + + $this->addFlash('success', 'Address added successfully'); + + return $this->redirectToRoute('app_list_case_addresses'); + } + + return $this->render( + 'internal/cases/addresses/add-case-address.html.twig', + array_merge( + $this->navLinks, + [ + 'title' => 'Add Case Address', + 'breadcrumbs' => [ + new Breadcrumb($this->generateUrl('app_list_case_addresses'), 'List Addresses'), + new Breadcrumb($this->generateUrl('app_case_add_address'), 'Add Case Address') + ], + 'notifications' => $this->msgs, + 'notificationCount' => $this->notificationCount, + 'form' => $form, + 'cases' => $cases, + ] + ) + ); + } + + #[Route('/addresses/edit/{id}', name: 'app_case_edit_address')] + public function editCaseAddress(Request $request, string $id): Response + { + $this->navLinks['case_itinerary'] = NavList::PRESENT_LINK; + $this->navLinks['case_list'] = 'nav-link text-dark'; + + $this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($this->getUser()); + $this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($this->getUser()); + + $ucs = $this->entityManager->getRepository(UserCase::class)->findBy(['user' => $this->getUser()]); + $lcs = $this->entityManager->getRepository(CaseLocation::class)->findBy(['location' => $id]); + + $inCases = []; + foreach ($lcs as $lc) { + $inCases[] = $lc->getMemberCase()->getId()->toString(); + } + + $cases = []; + foreach ($ucs as $uc) { + /** @var UserCase $uc */ + $cases[] = $uc->getMemberCase(); + } + $location = $this->entityManager->getRepository(Location::class)->find($id); + $form = $this->createForm(LocationFormType::class, $location); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + list($lat, $lon) = Libs::getLatLonFromGeoapify((string) $location); + $location->setLat($lat) + ->setLon($lon); + + $this->entityManager->flush(); + + $this->addFlash('success', 'Address updated successfully'); + + return $this->redirectToRoute('app_list_case_addresses'); + } + + return $this->render( + 'internal/cases/addresses/edit-case-address.html.twig', + array_merge( + $this->navLinks, + [ + 'title' => 'Edit Case Address', + 'breadcrumbs' => [ + new Breadcrumb($this->generateUrl('app_list_case_addresses'), 'List Case Addresses'), + new Breadcrumb($this->generateUrl('app_case_edit_address', ['id' => $id]), 'Edit Case Address') + ], + 'location' => $location, + 'cases' => $cases, + 'inCases' => $inCases, + 'form' => $form, + 'notifications' => $this->msgs, + 'notificationCount' => $this->notificationCount, + ] + ) + ); + } + + #[Route('/api/filter-address-by-case/{caseId}', name: 'ajax_filter_address_by_case')] + public function filterAddressByCase(string $caseId, Request $request): Response + { + $case = $this->entityManager->getRepository(MemberCase::class)->find($caseId); + $addresses = $this->entityManager->getRepository(Location::class)->getLocationsByCase($case); + + return $this->json($addresses); + } + #[Route('/api/case/{caseId}/user/{userId}', name: 'ajax_case_user_level_check')] public function checkUserCaseLevel(string $caseId, string $userId) : Response { diff --git a/src/Controller/ItineraryController.php b/src/Controller/ItineraryController.php new file mode 100644 index 0000000..12d5b4c --- /dev/null +++ b/src/Controller/ItineraryController.php @@ -0,0 +1,145 @@ +navLinks = NavList::LIST; + } + + #[Route('/itinerary/map', name: 'app_map_itinerary')] + public function mapItinerary(Request $request, #[CurrentUser()] ?User $user): Response + { + $this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user); + $this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user); + + $itineraries = $this->entityManager->getRepository(CaseItinerary::class)->findBy([ + 'memberCase' => $request->getPayload()->get('caseId'), + 'date' => new DateTime($request->getPayload()->get('caseDate')) + ]); + + $map = new Map('default'); + $map->center(new Point(39.768502, -86.157918)) + ->zoom(9) + ; + + $total_distance = 0; + $total_duration = 0; + + foreach ($itineraries as $itinerary) { + /** @var CaseItinerary $itinerary */ + $map->addPolyline(new Polyline( + points: $itinerary->getGPSPolyLines(), + infoWindow: new InfoWindow( + content: $itinerary->getMemberCase()->getCaseName() + ) + )); + + $total_distance += $itinerary->getDistance(); + $total_duration += $itinerary->getDuration()->s; + } + + return $this->render( + 'internal/cases/itinerary/map.html.twig', + array_merge( + $this->navLinks, + [ + 'breadcrumbs' => [ + new Breadcrumb($this->generateUrl('app_my_cases'), 'My Cases'), + ], + 'notifications' => $this->msgs, + 'notificationCount' => $this->notificationCount, + 'map' => $map, + 'total_distance' => $total_distance, + 'total_duration' => $total_duration, + ] + ) + ); + } + + #[Route('/api/get-case-locations/{caseId}', name: 'get_case_locations')] + public function createItinerary(string $caseId): Response + { + $case = $this->entityManager->getRepository(MemberCase::class)->find($caseId); + $cls = $this->entityManager->getRepository(CaseLocation::class)->getCaseLocations($case); + + $locations = []; + foreach ($cls as $cl) { + /** @var CaseLocation $cl */ + $locations[] = $cl->getLocation(); + } + + return $this->json($locations); + } + + #[Route('/api/add-location-to-itinerary', name: 'add_location_to_itinerary')] + public function addLocationToItinerary(Request $request, Session $session): Response + { + $case = $this->entityManager->getRepository(MemberCase::class)->find($request->getPayload()->get('caseId')); + $origin = $this->entityManager->getRepository(Location::class)->find($request->getPayload()->get('origin')); + $destination = $this->entityManager->getRepository(Location::class)->find($request->getPayload()->get('destination')); + $departure = $request->getPayload()->get('departure'); + $arrival = $request->getPayload()->get('arrival'); + $caseMileage = (bool) $request->getPayload()->get('caseMileage'); + $date = new DateTime($request->getPayload()->get('date')); + + $route = Libs::getRouteDistance($origin, $destination); + + if (!$route) { + return $this->json(['success' => false, 'message' => 'No route found']); + } + + $ci = new CaseItinerary(); + $ci->setMemberCase($case) + ->setDate($date) + ->setCaseMileage($caseMileage) + ->setOriginLocation($origin) + ->setDestLocation($destination) + ->setDeparture(new \DateTimeImmutable($departure)) + ->setArrival(new \DateTimeImmutable($arrival)) + ->setDistance($route->getDistance()) + ->setDuration($route->getDuration()) + ->setGpsRoute($route->getGeometry()) + ; + + $this->entityManager->persist($ci); + $this->entityManager->flush(); + + $session->getFlashBag()->add( + 'success', + 'Location added to itinerary' + ); + return $this->json(['success' => true, 'message' => 'Location added to itinerary']); + } +} diff --git a/src/Entity/CaseItinerary.php b/src/Entity/CaseItinerary.php new file mode 100644 index 0000000..344e4bf --- /dev/null +++ b/src/Entity/CaseItinerary.php @@ -0,0 +1,194 @@ +id; + } + + public function getDeparture(): ?\DateTimeInterface + { + return $this->departure; + } + + public function setDeparture(?\DateTimeInterface $departure): static + { + $this->departure = $departure; + + return $this; + } + + public function getOriginLocation(): ?Location + { + return $this->originLocation; + } + + public function setOriginLocation(?Location $originLocation): static + { + $this->originLocation = $originLocation; + + return $this; + } + + public function getArrival(): ?\DateTimeInterface + { + return $this->arrival; + } + + public function setArrival(?\DateTimeInterface $arrival): static + { + $this->arrival = $arrival; + + return $this; + } + + public function getDestLocation(): ?Location + { + return $this->destLocation; + } + + public function setDestLocation(?Location $destLocation): static + { + $this->destLocation = $destLocation; + + return $this; + } + + public function isCaseMileage(): ?bool + { + return $this->caseMileage; + } + + public function setCaseMileage(bool $caseMileage): static + { + $this->caseMileage = $caseMileage; + + return $this; + } + + public function getDuration(): ?DateInterval + { + return $this->duration; + } + + public function setDuration(?DateInterval $duration): static + { + //$this->calcDuration(); + $this->duration = $duration; + + return $this; + } + + public function calcDuration() + { + $this->duration = $this->departure - $this->arrival; + } + + public function getMemberCase(): ?MemberCase + { + return $this->memberCase; + } + + public function setMemberCase(?MemberCase $memberCase): static + { + $this->memberCase = $memberCase; + + return $this; + } + + public function getDate(): ?\DateTimeInterface + { + return $this->date; + } + + public function setDate(\DateTimeInterface $date): static + { + $this->date = $date; + + return $this; + } + + public function getDistance(): ?float + { + return $this->distance; + } + + public function setDistance(?float $distance): static + { + $this->distance = $distance; + + return $this; + } + + public function getGpsRoute(): ?array + { + return $this->gpsRoute; + } + + public function setGpsRoute(?array $gpsRoute): static + { + $this->gpsRoute = $gpsRoute; + + return $this; + } + + public function getGPSPolyLines(): array + { + $points = []; + foreach ($this->gpsRoute as $route) { + $points[] = new Point($route['lat'], $route['lon']); + } + return $points; + } +} diff --git a/src/Entity/CaseLocation.php b/src/Entity/CaseLocation.php new file mode 100644 index 0000000..7a89c5e --- /dev/null +++ b/src/Entity/CaseLocation.php @@ -0,0 +1,55 @@ +id; + } + + public function getMemberCase(): ?MemberCase + { + return $this->memberCase; + } + + public function setMemberCase(?MemberCase $memberCase): static + { + $this->memberCase = $memberCase; + + return $this; + } + + public function getLocation(): ?Location + { + return $this->location; + } + + public function setLocation(?Location $location): static + { + $this->location = $location; + + return $this; + } +} diff --git a/src/Entity/Location.php b/src/Entity/Location.php new file mode 100644 index 0000000..e9a9e33 --- /dev/null +++ b/src/Entity/Location.php @@ -0,0 +1,140 @@ +id; + } + + public function getName(): ?string + { + return $this->name; + } + + public function setName(string $name): static + { + $this->name = $name; + + return $this; + } + + public function getAddress(): ?string + { + return $this->address; + } + + public function setAddress(string $address): static + { + $this->address = $address; + + return $this; + } + + public function getCity(): ?string + { + return $this->city; + } + + public function setCity(?string $city): static + { + $this->city = $city; + + return $this; + } + + public function getState(): ?State + { + return $this->state; + } + + public function setState(?State $state): static + { + $this->state = $state; + + return $this; + } + + public function getZip(): ?int + { + return $this->zip; + } + + public function setZip(?int $zip): static + { + $this->zip = $zip; + + return $this; + } + + public function getFormattedAddress(): string + { + return "{$this->address}
{$this->city}, {$this->state->value} {$this->zip}"; + } + + public function getLat(): ?string + { + return $this->lat; + } + + public function setLat(?string $lat): static + { + $this->lat = $lat; + + return $this; + } + + public function getLon(): ?string + { + return $this->lon; + } + + public function setLon(?string $lon): static + { + $this->lon = $lon; + + return $this; + } + + public function __toString(): string + { + return "{$this->address} {$this->city}, {$this->state->value} {$this->zip}"; + } +} diff --git a/src/Libs/Libs.php b/src/Libs/Libs.php index 5bcc071..da82a44 100644 --- a/src/Libs/Libs.php +++ b/src/Libs/Libs.php @@ -2,6 +2,8 @@ namespace App\Libs; +use App\Entity\Location; + class Libs { public static function getLatLonFromGeoapify($address): ?array @@ -24,7 +26,7 @@ class Libs return null; } - public static function getRoute($lat1, $lon1, $lat2, $lon2): ?array + public static function getRoute($lat1, $lon1, $lat2, $lon2): ?Route { $params = [ 'waypoints' => "{$lat1},{$lon1}|{$lat2},{$lon2}", @@ -34,7 +36,6 @@ class Libs 'apiKey' => $_ENV['GEOAPIFY_API_KEY'] ]; - $url = "https://api.geoapify.com/v1/routing?".http_build_query($params); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); @@ -43,10 +44,18 @@ class Libs curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); $result = curl_exec($ch); curl_close($ch); - $result = json_decode($result, true); - dd($result); - if (isset($result['features'][0]['geometry']['coordinates'])) { - $route = $result['features'][0]['geometry']['coordinates']; + $route = new Route(json_decode($result)); + + if (is_a($route, Route::class)) { + return $route; + } + return null; + } + + public static function getRouteDistance(Location $origin, Location $destination): ?Route + { + $route = self::getRoute($origin->getLat(), $origin->getLon(), $destination->getLat(), $destination->getLon()); + if ($route) { return $route; } return null; diff --git a/src/Libs/Route.php b/src/Libs/Route.php new file mode 100644 index 0000000..c2dcc77 --- /dev/null +++ b/src/Libs/Route.php @@ -0,0 +1,47 @@ +distance = $route->results[0]->distance; + $this->duration = $route->results[0]->time; + $this->geometry = $route->results[0]->geometry[0]; + } + + public function getDuration(): ?DateInterval + { + $startDate = new DateTime("@0"); + $endDate = new DateTime("@{$this->duration}"); + $dur = $startDate->diff($endDate); + + return $dur; + } + + public function getDurationString(): string + { + return $this->getDuration()->format('%H:%I:%S'); + } + + public function getDistance(): float + { + return $this->distance; + } + + public function getGeometry(): array + { + return $this->geometry; + } +} diff --git a/src/Repository/CaseItineraryRepository.php b/src/Repository/CaseItineraryRepository.php new file mode 100644 index 0000000..3d042f5 --- /dev/null +++ b/src/Repository/CaseItineraryRepository.php @@ -0,0 +1,43 @@ + + */ +class CaseItineraryRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, CaseItinerary::class); + } + + // /** + // * @return CaseLocation[] Returns an array of CaseLocation objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('c') + // ->andWhere('c.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('c.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?CaseLocation + // { + // return $this->createQueryBuilder('c') + // ->andWhere('c.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/src/Repository/CaseLocationRepository.php b/src/Repository/CaseLocationRepository.php new file mode 100644 index 0000000..a964e33 --- /dev/null +++ b/src/Repository/CaseLocationRepository.php @@ -0,0 +1,57 @@ + + */ +class CaseLocationRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, CaseLocation::class); + } + + public function getCaseLocations(MemberCase $case): array + { + return $this->createQueryBuilder('cl') + ->leftJoin(Location::class, 'l', 'WITH', 'l.id = cl.location') + ->andWhere('cl.memberCase = :case') + ->setParameter('case', $case->getId()->toBinary()) + ->orderBy('l.name', 'ASC') + ->getQuery() + ->getResult() + ; + } + + // /** + // * @return CaseLocation[] Returns an array of CaseLocation objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('c') + // ->andWhere('c.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('c.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?CaseLocation + // { + // return $this->createQueryBuilder('c') + // ->andWhere('c.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/src/Repository/LocationRepository.php b/src/Repository/LocationRepository.php new file mode 100644 index 0000000..d960771 --- /dev/null +++ b/src/Repository/LocationRepository.php @@ -0,0 +1,74 @@ + + */ +class LocationRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, Location::class); + } + + public function getUserLocations(User $user): array + { + $query = $this->createQueryBuilder('location') + ->leftJoin(CaseLocation::class, 'cl', 'WITH', 'cl.location = location.id') + ->leftJoin(UserCase::class, 'uc', 'WITH', 'uc.memberCase = cl.memberCase') + ->andWhere('uc.user = :user') + ->setParameter('user', $user->getId()->toBinary()) + ->orderBy('location.name', 'ASC') + ->getQuery() + ->getResult() + ; + + return $query; + } + + public function getLocationsByCase(MemberCase $case): array + { + return $this->createQueryBuilder('location') + ->leftJoin(CaseLocation::class, 'cl', 'WITH', 'cl.location = location.id') + ->andWhere('cl.memberCase = :case') + ->setParameter('case', $case->getId()->toBinary()) + ->orderBy('location.name', 'ASC') + ->getQuery() + ->getResult() + ; + } + + // /** + // * @return Locations[] Returns an array of Locations objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('l') + // ->andWhere('l.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('l.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?Locations + // { + // return $this->createQueryBuilder('l') + // ->andWhere('l.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/templates/internal/cases/addresses/add-case-address.html.twig b/templates/internal/cases/addresses/add-case-address.html.twig new file mode 100644 index 0000000..8444dd9 --- /dev/null +++ b/templates/internal/cases/addresses/add-case-address.html.twig @@ -0,0 +1,76 @@ +{% extends 'base.html.twig' %} + +{% block body %} + {{ block('nav', 'internal/libs/nav.html.twig') }} + +
+ {{ block('topnav', 'internal/libs/top-nav.html.twig') }} + +
+ +
+
+

Add Address

+

+
+
+
+ {{ form_errors(form) }} + + {{ form_start(form) }} +
+
+
+ + +
+ +
+ {% for c in cases %} +
+ + +
+ {% endfor %} +
+
+
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
+
+
+ +
+
+ {{ form_end(form) }} +
+
+
+
+
+{% endblock %} diff --git a/templates/internal/cases/addresses/edit-case-address.html.twig b/templates/internal/cases/addresses/edit-case-address.html.twig new file mode 100644 index 0000000..a4aee4a --- /dev/null +++ b/templates/internal/cases/addresses/edit-case-address.html.twig @@ -0,0 +1,76 @@ +{% extends 'base.html.twig' %} + +{% block body %} + {{ block('nav', 'internal/libs/nav.html.twig') }} + +
+ {{ block('topnav', 'internal/libs/top-nav.html.twig') }} + +
+ +
+
+

Edit Address

+

{{ location.name }}

+
+
+
+ {{ form_start(form) }} + + {{ form_errors(form) }} +
+
+
+ + +
+ +
+ {% for c in cases %} +
+ + +
+ {% endfor %} +
+
+
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
+
+
+ +
+
+ {{ form_end(form) }} +
+
+
+
+
+{% endblock %} diff --git a/templates/internal/cases/addresses/list-case-addresses.html.twig b/templates/internal/cases/addresses/list-case-addresses.html.twig new file mode 100644 index 0000000..854e286 --- /dev/null +++ b/templates/internal/cases/addresses/list-case-addresses.html.twig @@ -0,0 +1,149 @@ +{% extends 'base.html.twig' %} + +{% block body %} + {{ block('nav', 'internal/libs/nav.html.twig') }} + +
+ {{ block('topnav', 'internal/libs/top-nav.html.twig') }} + +
+
+
+
+
+
+
+
Case Address List
+
+
+
+ + + +
+ + +
+
+
+
+
+ Filters: + + +
+
+ + + + + + + + + + + {% for l in addresses %} + + + + + + + {% endfor %} + +
NameAddressLat/Lon
+
+
+
+ {{ l.name }} +
+
+
+
+ {{ l.getFormattedAddress()|raw }} + + {{ l.lat }}/{{ l.lon }} + + + edit + +
+
+
+
+
+
+
+ + +
+{% endblock %} + +{% block page_js %} + +{% endblock %} diff --git a/templates/internal/cases/itinerary/map.html.twig b/templates/internal/cases/itinerary/map.html.twig new file mode 100644 index 0000000..882aef9 --- /dev/null +++ b/templates/internal/cases/itinerary/map.html.twig @@ -0,0 +1,20 @@ +{% extends 'base.html.twig' %} + +{% block body %} + {{ block('nav', 'internal/libs/nav.html.twig') }} + +
+ {{ block('topnav', 'internal/libs/top-nav.html.twig') }} + +
+
+ Totals: + {{ total_distance }} + / + {{ total_duration }} +
+ {{ ux_map(map, {style: 'height: 600px', 'data-controller': 'my-map'}) }} +
+ +
+{% endblock %}