diff --git a/src/Controller/CommunityResourceController.php b/src/Controller/CommunityResourceController.php
new file mode 100644
index 0000000..2b5d3a9
--- /dev/null
+++ b/src/Controller/CommunityResourceController.php
@@ -0,0 +1,138 @@
+navLinks = NavList::LIST;
+ $this->navLinks['community_resources'] = NavList::PRESENT_LINK;
+ }
+
+ #[Route('/resource/list', name: 'app_community_resource')]
+ public function list(#[CurrentUser()] User $user): Response
+ {
+ $rsc = $this->entityManager->getRepository(CommunityResource::class)->findAll();
+
+ return $this->render(
+ 'internal/community_resource/list.html.twig',
+ array_merge(
+ $this->navLinks,
+ [
+ 'breadcrumbs' => [
+ new Breadcrumb('#', 'Community Resources')
+ ],
+ 'resources' => $rsc,
+ 'notifications' => $user->retrieveUnreadNotifications(),
+ ]
+ )
+ );
+ }
+
+ #[Route('/resource/map', name: 'app_community_resource_map')]
+ public function map(): Response
+ {
+ return $this->render('internal/community_resource/map.html.twig', [
+ ]);
+ }
+
+ #[Route('/resource/add', name: 'app_community_resource_add')]
+ public function add(#[CurrentUser()] User $user, Request $request): Response
+ {
+ $form = $this->createForm(ResourceFormType::class);
+ $form->handleRequest($request);
+
+ if ($form->isSubmitted() && $form->isValid()) {
+ $rsc = $form->getData();
+ $this->entityManager->persist($rsc);
+ $this->entityManager->flush();
+
+ return $this->redirectToRoute('app_community_resource');
+ }
+
+ return $this->render(
+ 'internal/community_resource/add.html.twig',
+ array_merge(
+ $this->navLinks,
+ [
+ 'form' => $form,
+ 'breadcrumbs' => [
+ new Breadcrumb($this->generateUrl('app_community_resource'), 'List Resources'),
+ new Breadcrumb('#', 'Add Resource')
+ ],
+ 'notifications' => $user->retrieveUnreadNotifications(),
+ ]
+ )
+ );
+
+ }
+
+ #[Route('/resource/edit/{id}', name: 'app_community_resource_edit')]
+ public function edit(string $id, #[CurrentUser()] User $user, Request $request): Response
+ {
+ $rsc = $this->entityManager->getRepository(CommunityResource::class)->find($id);
+ $form = $this->createForm(ResourceFormType::class, $rsc);
+
+ $form->handleRequest($request);
+
+ if ($form->isSubmitted() && $form->isValid()) {
+ $this->entityManager->flush();
+
+ return $this->redirectToRoute('app_community_resource');
+ }
+
+ return $this->render(
+ 'internal/community_resource/edit.html.twig',
+ array_merge(
+ $this->navLinks,
+ [
+ 'form' => $form,
+ 'breadcrumbs' => [
+ new Breadcrumb($this->generateUrl('app_community_resource'), 'List Resources'),
+ new Breadcrumb('#', 'Edit Resource')
+ ],
+ 'notifications' => $user->retrieveUnreadNotifications(),
+ ]
+ )
+ );
+
+ }
+
+ #[Route('/resource/download/{id}', name: 'app_community_resource_download')]
+ public function download(string $id): Response
+ {
+ /** @var CommunityResource $rsc */
+ $rsc = $this->entityManager->getRepository(CommunityResource::class)->find($id);
+
+ if (!$rsc) {
+ $this->addFlash('error', 'Resource not found.');
+ return $this->redirectToRoute('app_community_resource');
+ }
+
+ return new Response($rsc->generateVCard(), 200, [
+ 'Content-Type' => 'text/vcf',
+ 'Content-Disposition' => 'attachment; filename="' . str_replace(' ', '', $rsc->getName()) . '.vcf"',
+ 'Content-Length' => strlen($rsc->generateVCard()),
+ 'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
+ 'Expires' => '0',
+ 'Pragma' => 'public',
+ 'Content-Transfer-Encoding' => 'binary'
+ ]);
+ }
+}
diff --git a/src/Entity/CommunityResource.php b/src/Entity/CommunityResource.php
new file mode 100644
index 0000000..8533d65
--- /dev/null
+++ b/src/Entity/CommunityResource.php
@@ -0,0 +1,626 @@
+today = new DateTime('now', new DateTimeZone('America/New_York'));
+ }
+
+ public function getId(): ?Uuid
+ {
+ return $this->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 getAddress2(): ?string
+ {
+ return $this->address2;
+ }
+
+ public function setAddress2(?string $address2): static
+ {
+ $this->address2 = $address2;
+
+ 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 getCounty(): ?County
+ {
+ return $this->county;
+ }
+
+ public function setCounty(County $county): static
+ {
+ $this->county = $county;
+
+ return $this;
+ }
+
+ public function getFormattedAddress(): ?string
+ {
+ return $this->address .
+ ($this->address2 ? ' ' . $this->address2 : '') . '
' .
+ $this->city . ', ' . $this->state->value . ' ' . $this->zip;
+ }
+
+ public function getPhone(): ?string
+ {
+ return $this->phone;
+ }
+
+ public function setPhone(?string $phone): static
+ {
+ $this->phone = $phone;
+
+ return $this;
+ }
+
+ public function getEmail(): ?string
+ {
+ return $this->email;
+ }
+
+ public function setEmail(?string $email): static
+ {
+ $this->email = $email;
+
+ return $this;
+ }
+
+ public function getUrl(): ?string
+ {
+ return $this->url;
+ }
+
+ public function setUrl(?string $url): static
+ {
+ $this->url = $url;
+
+ return $this;
+ }
+
+ public function urlString(): ?string
+ {
+ if (preg_match("/facebook/i", $this->url)) {
+ return "";
+ } else {
+ return "";
+ }
+ return null;
+ }
+
+ public function getContactCard(): ?string
+ {
+ $formattedPhone = ($this->phone ? '(' . substr($this->phone, 0, 3) . ') ' . substr($this->phone, 3, 3) . '-' . substr($this->phone, 6) : '');
+ return ($this->email ? "$this->email
" : '') .
+ ($this->phone ? "$formattedPhone" : '');
+ }
+
+ public function generateVCard(): string
+ {
+ return 'BEGIN:VCARD' .
+ "\nVERSION:3.0" .
+ "\nN:$this->name" .
+ "\nFN:$this->name" .
+ "\nORG:$this->name" .
+ "\nADR;TYPE=WORK:;;$this->address;$this->city;{$this->state->value};$this->zip" .
+ ($this->phone ? "\nTEL;TYPE=WORK,VOICE:$this->phone" : null) .
+ ($this->email ? "\nEMAIL;TYPE=WORK,INTERNET:$this->email" : null) .
+ ($this->url ? "\nURL:$this->url" : null) .
+ "\nNOTE:$this->notes" .
+ "\nREV:" . date('c') .
+ "\nEND:VCARD";
+ }
+
+ public function getMonOpen(): ?\DateTimeInterface
+ {
+ return $this->monOpen;
+ }
+
+ public function setMonOpen(?\DateTimeInterface $monOpen): static
+ {
+ $this->monOpen = $monOpen;
+
+ return $this;
+ }
+
+ public function getMonClose(): ?\DateTimeInterface
+ {
+ return $this->monClose;
+ }
+
+ public function setMonClose(?\DateTimeInterface $monClose): static
+ {
+ $this->monClose = $monClose;
+
+ return $this;
+ }
+
+ public function mon(): ?string
+ {
+ if (!$this->monOpen || !$this->monClose) {
+ return 'C';
+ }
+
+ $closeAt = new DateTime($this->today->format('Y-m-d') . ' ' . $this->monClose->format('H:i:s'));
+ if ($closeAt <= new DateTime()) {
+ return 'C';
+ }
+
+ return $this->monOpen->format('g:i A') . '-' . $this->monClose->format('g:i A');
+ }
+
+ public function getTueOpen(): ?\DateTimeInterface
+ {
+ return $this->tueOpen;
+ }
+
+ public function setTueOpen(?\DateTimeInterface $tueOpen): static
+ {
+ $this->tueOpen = $tueOpen;
+
+ return $this;
+ }
+
+ public function getTueClose(): ?\DateTimeInterface
+ {
+ return $this->tueClose;
+ }
+
+ public function setTueClose(?\DateTimeInterface $tueClose): static
+ {
+ $this->tueClose = $tueClose;
+
+ return $this;
+ }
+
+ public function tue(): ?string
+ {
+ if (!$this->tueOpen || !$this->tueClose) {
+ return 'C';
+ }
+
+ $closeAt = new DateTime($this->today->format('Y-m-d') . ' ' . $this->tueClose->format('H:i:s'));
+ if ($closeAt <= new DateTime()) {
+ return 'C';
+ }
+
+ return $this->tueOpen->format('g:i A') . '-' . $this->tueClose->format('g:i A');
+ }
+
+ public function getWedOpen(): ?\DateTimeInterface
+ {
+ return $this->wedOpen;
+ }
+
+ public function setWedOpen(?\DateTimeInterface $wedOpen): static
+ {
+ $this->wedOpen = $wedOpen;
+
+ return $this;
+ }
+
+ public function getWedClose(): ?\DateTimeInterface
+ {
+ return $this->wedClose;
+ }
+
+ public function setWedClose(?\DateTimeInterface $wedClose): static
+ {
+ $this->wedClose = $wedClose;
+
+ return $this;
+ }
+
+ public function wed(): ?string
+ {
+ if (!$this->wedOpen || !$this->wedClose) {
+ return 'C';
+ }
+
+ $closeAt = new DateTime($this->today->format('Y-m-d') . ' ' . $this->wedClose->format('H:i:s'));
+ if ($closeAt <= new DateTime()) {
+ return 'C';
+ }
+
+ return $this->wedOpen->format('g:i A') . '-' . $this->wedClose->format('g:i A');
+ }
+
+ public function getThuOpen(): ?\DateTimeInterface
+ {
+ return $this->thuOpen;
+ }
+
+ public function setThuOpen(?\DateTimeInterface $thuOpen): static
+ {
+ $this->thuOpen = $thuOpen;
+
+ return $this;
+ }
+
+ public function getThuClose(): ?\DateTimeInterface
+ {
+ return $this->thuClose;
+ }
+
+ public function setThuClose(?\DateTimeInterface $thuClose): static
+ {
+ $this->thuClose = $thuClose;
+
+ return $this;
+ }
+
+ public function thu(): ?string
+ {
+ if (!$this->thuOpen || !$this->thuClose) {
+ return 'C';
+ }
+
+ $closeAt = new DateTime($this->today->format('Y-m-d') . ' ' . $this->thuClose->format('H:i:s'));
+ if ($closeAt <= new DateTime()) {
+ return 'C';
+ }
+
+ return $this->thuOpen->format('g:i A') . '-' . $this->thuClose->format('g:i A');
+ }
+
+ public function getFriOpen(): ?\DateTimeInterface
+ {
+ return $this->friOpen;
+ }
+
+ public function setFriOpen(?\DateTimeInterface $friOpen): static
+ {
+ $this->friOpen = $friOpen;
+
+ return $this;
+ }
+
+ public function getFriClose(): ?\DateTimeInterface
+ {
+ return $this->friClose;
+ }
+
+ public function setFriClose(?\DateTimeInterface $friClose): static
+ {
+ $this->friClose = $friClose;
+
+ return $this;
+ }
+
+ public function fri(): ?string
+ {
+ if (!$this->friOpen || !$this->friClose) {
+ return 'C';
+ }
+
+ $closeAt = new DateTime($this->today->format('Y-m-d') . ' ' . $this->friClose->format('H:i:s'));
+ if ($closeAt <= new DateTime()) {
+ return 'C';
+ }
+
+ return $this->friOpen->format('g:i A') . '-' . $this->friClose->format('g:i A');
+ }
+
+ public function getSatOpen(): ?\DateTimeInterface
+ {
+ return $this->satOpen;
+ }
+
+ public function setSatOpen(?\DateTimeInterface $satOpen): static
+ {
+ $this->satOpen = $satOpen;
+
+ return $this;
+ }
+
+ public function getSatClose(): ?\DateTimeInterface
+ {
+ return $this->satClose;
+ }
+
+ public function setSatClose(?\DateTimeInterface $satClose): static
+ {
+ $this->satClose = $satClose;
+
+ return $this;
+ }
+
+ public function sat(): ?string
+ {
+ if (!$this->satOpen || !$this->satClose) {
+ return 'C';
+ }
+
+ $closeAt = new DateTime($this->today->format('Y-m-d') . ' ' . $this->satClose->format('H:i:s'));
+ if ($closeAt <= new DateTime()) {
+ return 'C';
+ }
+
+ return $this->satOpen->format('g:i A') . '-' . $this->satClose->format('g:i A');
+ }
+
+ public function getSunOpen(): ?\DateTimeInterface
+ {
+ return $this->sunOpen;
+ }
+
+ public function setSunOpen(?\DateTimeInterface $sunOpen): static
+ {
+ $this->sunOpen = $sunOpen;
+
+ return $this;
+ }
+
+ public function getSunClose(): ?\DateTimeInterface
+ {
+ return $this->sunClose;
+ }
+
+ public function setSunClose(?\DateTimeInterface $sunClose): static
+ {
+ $this->sunClose = $sunClose;
+
+ return $this;
+ }
+
+ public function sun(): ?string
+ {
+ if (!$this->sunOpen || !$this->sunClose) {
+ return 'C';
+ }
+
+ $closeAt = new DateTime($this->today->format('Y-m-d') . ' ' . $this->sunClose->format('H:i:s'));
+ if ($closeAt <= new DateTime()) {
+ return 'C';
+ }
+
+ return $this->sunOpen->format('g:i A') . '-' . $this->sunClose->format('g:i A');
+ }
+
+ public function getHours(): ?string
+ {
+ $this->today = new DateTime('now', new DateTimeZone('America/New_York'));
+ switch ($this->today->format('w')) {
+ case 0:
+ return $this->sun();
+ case 1:
+ return $this->mon();
+ case 2:
+ return $this->tue();
+ case 3:
+ return $this->wed();
+ case 4:
+ return $this->thu();
+ case 5:
+ return $this->fri();
+ case 6:
+ return $this->sat();
+ }
+ }
+
+ public function getFormattedHours(): ?string
+ {
+ $mon = 'CLOSED';
+ $tue = 'CLOSED';
+ $wed = 'CLOSED';
+ $thu = 'CLOSED';
+ $fri = 'CLOSED';
+ $sat = 'CLOSED';
+ $sun = 'CLOSED';
+
+ if ($this->monOpen && $this->monClose) {
+ $mon = $this->monOpen->format('g:i A') . '-' . $this->monClose->format('g:i A');
+ }
+ if ($this->tueOpen && $this->tueClose) {
+ $tue = $this->tueOpen->format('g:i A') . '-' . $this->tueClose->format('g:i A');
+ }
+ if ($this->wedOpen && $this->wedClose) {
+ $wed = $this->wedOpen->format('g:i A') . '-' . $this->wedClose->format('g:i A');
+ }
+ if ($this->thuOpen && $this->thuClose) {
+ $thu = $this->thuOpen->format('g:i A') . '-' . $this->thuClose->format('g:i A');
+ }
+ if ($this->friOpen && $this->friClose) {
+ $fri = $this->friOpen->format('g:i A') . '-' . $this->friClose->format('g:i A');
+ }
+ if ($this->satOpen && $this->satClose) {
+ $sat = $this->satOpen->format('g:i A') . '-' . $this->satClose->format('g:i A');
+ }
+ if ($this->sunOpen && $this->sunClose) {
+ $sun = $this->sunOpen->format('g:i A') . '-' . $this->sunClose->format('g:i A');
+ }
+
+ return <<Sun: {$sun}
Mon: {$mon}
+Tue: {$tue}
+Wed: {$wed}
+Thu: {$thu}
+Fri: {$fri}
+Sat: {$sat}
+ HTML; + } + + public function getNotes(): ?string + { + return $this->notes; + } + + public function setNotes(?string $notes): static + { + $this->notes = $notes; + + return $this; + } + + public function getServicesAvailable(): ?string + { + return $this->servicesAvailable; + } + + public function setServicesAvailable(?string $servicesAvailable): static + { + $this->servicesAvailable = $servicesAvailable; + + return $this; + } +} diff --git a/src/Enums/State.php b/src/Enums/State.php new file mode 100644 index 0000000..a1e923d --- /dev/null +++ b/src/Enums/State.php @@ -0,0 +1,58 @@ +add('name', TextType::class, [ + 'required' => true, + ]) + ->add('address', TextType::class, [ + 'required' => true, + ]) + ->add('address2') + ->add('city', TextType::class, [ + 'required' => true, + ]) + ->add('state', EnumType::class, [ + 'class' => State::class, + ]) + ->add('zip', NumberType::class) + ->add('county', EnumType::class, [ + 'class' => County::class, + ]) + ->add('phone') + ->add('email', EmailType::class) + ->add('url', UrlType::class) + ->add('monOpen', TimeType::class, [ + 'widget' => 'single_text', + ]) + ->add('monClose', TimeType::class, [ + 'widget' => 'single_text', + ]) + ->add('tueOpen', TimeType::class, [ + 'widget' => 'single_text', + ]) + ->add('tueClose', TimeType::class, [ + 'widget' => 'single_text', + ]) + ->add('wedOpen', TimeType::class, [ + 'widget' => 'single_text', + ]) + ->add('wedClose', TimeType::class, [ + 'widget' => 'single_text', + ]) + ->add('thuOpen', TimeType::class, [ + 'widget' => 'single_text', + ]) + ->add('thuClose', TimeType::class, [ + 'widget' => 'single_text', + ]) + ->add('friOpen', TimeType::class, [ + 'widget' => 'single_text', + ]) + ->add('friClose', TimeType::class, [ + 'widget' => 'single_text', + ]) + ->add('satOpen', TimeType::class, [ + 'widget' => 'single_text', + ]) + ->add('satClose', TimeType::class, [ + 'widget' => 'single_text', + ]) + ->add('sunOpen', TimeType::class, [ + 'widget' => 'single_text', + ]) + ->add('sunClose', TimeType::class, [ + 'widget' => 'single_text', + ]) + ->add('notes') + ->add('servicesAvailable') + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => CommunityResource::class, + ]); + } +} diff --git a/src/Libs/NavList.php b/src/Libs/NavList.php index 0a39eba..8a9f5aa 100644 --- a/src/Libs/NavList.php +++ b/src/Libs/NavList.php @@ -14,6 +14,7 @@ class NavList 'add_user' => 'nav-link text-dark', 'referral_sources' => 'nav-link text-dark', 'case_notes' => 'nav-link text-dark', + 'community_resource' => 'nav-link text-dark', ]; public const PRESENT_LINK = 'nav-link text-white active bg-gradient-dark'; diff --git a/src/Repository/CommunityResourceRepository.php b/src/Repository/CommunityResourceRepository.php new file mode 100644 index 0000000..9b083a2 --- /dev/null +++ b/src/Repository/CommunityResourceRepository.php @@ -0,0 +1,43 @@ + + */ +class CommunityResourceRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, CommunityResource::class); + } + + // /** + // * @return CommunityResource[] Returns an array of CommunityResource 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): ?CommunityResource + // { + // return $this->createQueryBuilder('c') + // ->andWhere('c.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/templates/internal/community_resource/add.html.twig b/templates/internal/community_resource/add.html.twig new file mode 100644 index 0000000..51bf6f0 --- /dev/null +++ b/templates/internal/community_resource/add.html.twig @@ -0,0 +1,165 @@ +{% extends 'base.html.twig' %} + +{% block title %}Community Resources +{% endblock %} + +{% block body %} + {{ block('nav', 'internal/libs/nav.html.twig') }} + +Name | +Address | +Contact Info | +Hours | ++ |
---|---|---|---|---|
{{ r.name }}
+ {% if r.url %}
+ {{ r.urlString|raw }} + {% endif %} + |
+ {{ r.getFormattedAddress()|raw }} | +{{ r.getContactCard()|raw }} | +{{ r.getHours() }} | ++ + edit + + + import_contacts + + | +