Compare commits

...

17 Commits

Author SHA1 Message Date
55b1ef4f3d add leaflet libraries to importmap 2024-12-22 23:08:02 +00:00
c0a1929892 add leaflet css and js for mapping functionality 2024-12-22 23:07:05 +00:00
c7560e8e40 add note signing templates and note viewing after signing 2024-12-22 23:06:32 +00:00
7bcba9a930 add columns to note when supervisor and case worker signed staff notes and update available buttons 2024-12-22 23:05:55 +00:00
03352f9b28 remove recommendations as that is filled out by supervisor 2024-12-22 23:05:01 +00:00
b75a02973d add info for supervisor 2024-12-22 23:04:14 +00:00
2d5f395368 make 'Staff My Cases' available to all case workers 2024-12-22 23:03:32 +00:00
226818511f finish first draft of mapping for resources 2024-12-22 23:02:50 +00:00
e84e954164 add button to open map, finish county filtering 2024-12-22 23:02:32 +00:00
9cc469b5f8 add doctrine fixtures and faker to dev for testing, and add stimulus bundle and ux-map to prod 2024-12-22 23:01:46 +00:00
2869f3e03d Complete first draft of staff controller 2024-12-22 23:00:29 +00:00
af67d79a46 Add new date/time objects to store when reports signed by supervisor and case worker 2024-12-22 22:59:43 +00:00
e4b1704519 Add new method to create message back to worker when supervisor signs report 2024-12-22 22:59:05 +00:00
9526156d16 Add supervisor staff notes form and remove recommendations from case worker form 2024-12-22 22:58:33 +00:00
91110c037e Add method to retrieve ordered staff notes 2024-12-22 22:57:52 +00:00
c5b8148f00 Add mapping for community resources 2024-12-22 22:57:32 +00:00
7ae335a716 Add stimulus and ux-map bundles 2024-12-22 22:45:33 +00:00
24 changed files with 795 additions and 84 deletions

View File

@ -35,10 +35,13 @@
"symfony/runtime": "7.2.*", "symfony/runtime": "7.2.*",
"symfony/security-bundle": "7.2.*", "symfony/security-bundle": "7.2.*",
"symfony/serializer": "7.2.*", "symfony/serializer": "7.2.*",
"symfony/stimulus-bundle": "^2.22",
"symfony/string": "7.2.*", "symfony/string": "7.2.*",
"symfony/translation": "7.2.*", "symfony/translation": "7.2.*",
"symfony/twig-bundle": "7.2.*", "symfony/twig-bundle": "7.2.*",
"symfony/uid": "7.2.*", "symfony/uid": "7.2.*",
"symfony/ux-leaflet-map": "^2.22",
"symfony/ux-map": "^2.22",
"symfony/validator": "7.2.*", "symfony/validator": "7.2.*",
"symfony/web-link": "7.2.*", "symfony/web-link": "7.2.*",
"symfony/yaml": "7.2.*", "symfony/yaml": "7.2.*",
@ -97,6 +100,8 @@
} }
}, },
"require-dev": { "require-dev": {
"doctrine/doctrine-fixtures-bundle": "^4.0",
"fakerphp/faker": "^1.24",
"phpunit/phpunit": "^9.5", "phpunit/phpunit": "^9.5",
"symfony/browser-kit": "7.2.*", "symfony/browser-kit": "7.2.*",
"symfony/css-selector": "7.2.*", "symfony/css-selector": "7.2.*",

View File

@ -12,4 +12,6 @@ return [
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true],
Symfony\UX\Map\UXMapBundle::class => ['all' => true],
]; ];

View File

@ -0,0 +1,3 @@
ux_map:
# https://symfony.com/bundles/ux-map/current/index.html#available-renderers
renderer: "%env(resolve:default::UX_MAP_DSN)%"

View File

@ -22,7 +22,14 @@ return [
'@symfony/stimulus-bundle' => [ '@symfony/stimulus-bundle' => [
'path' => './vendor/symfony/stimulus-bundle/assets/dist/loader.js', 'path' => './vendor/symfony/stimulus-bundle/assets/dist/loader.js',
], ],
'@hotwired/turbo' => [ 'leaflet' => [
'version' => '7.3.0', 'version' => '1.9.4',
],
'leaflet/dist/leaflet.min.css' => [
'version' => '1.9.4',
'type' => 'css',
],
'@symfony/ux-leaflet-map' => [
'path' => './vendor/symfony/ux-leaflet-map/assets/dist/map_controller.js',
], ],
]; ];

View File

@ -7,6 +7,7 @@ use App\Entity\Messages;
use App\Entity\User; use App\Entity\User;
use App\Form\ResourceFormType; use App\Form\ResourceFormType;
use App\Libs\Breadcrumb; use App\Libs\Breadcrumb;
use App\Libs\Libs;
use App\Libs\NavList; use App\Libs\NavList;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@ -14,7 +15,10 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser; use Symfony\Component\Security\Http\Attribute\CurrentUser;
use Symfony\Component\Validator\Constraints\Regex; use Symfony\UX\Map\InfoWindow;
use Symfony\UX\Map\Map;
use Symfony\UX\Map\Marker;
use Symfony\UX\Map\Point;
class CommunityResourceController extends AbstractController class CommunityResourceController extends AbstractController
{ {
@ -59,10 +63,42 @@ class CommunityResourceController extends AbstractController
} }
#[Route('/resource/map', name: 'app_community_resource_map')] #[Route('/resource/map', name: 'app_community_resource_map')]
public function map(): Response public function map(#[CurrentUser()] User $user): Response
{ {
return $this->render('internal/community_resource/map.html.twig', [ $this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user);
]); $this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user);
$rcs = $this->entityManager->getRepository(CommunityResource::class)->findAll();
$map = new Map('default');
$map->center(new Point(39.768502, -86.157918))
->zoom(9)
;
foreach ($rcs as $rsc) {
$map->addMarker(new Marker(
position: new Point($rsc->getLat(), $rsc->getLon()),
title: $rsc->getName(),
infoWindow: new InfoWindow(
content: "{$rsc->getName()}<br>{$rsc->getAddress()}, {$rsc->getCity()}, {$rsc->getState()->value} {$rsc->getZip()}<br>Services: " . $rsc->getServicesAvailable()
)
));
}
return $this->render(
'internal/community_resource/map.html.twig',
array_merge(
$this->navLinks,
[
'map' => $map,
'breadcrumbs' => [
new Breadcrumb('#', 'Community Resources')
],
'notifications' => $this->msgs,
'notificationCount' => $this->notificationCount,
]
)
);
} }
#[Route('/resource/add', name: 'app_community_resource_add')] #[Route('/resource/add', name: 'app_community_resource_add')]
@ -75,7 +111,21 @@ class CommunityResourceController extends AbstractController
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
/** @var CommunityResource $rsc */
$rsc = $form->getData(); $rsc = $form->getData();
$res = Libs::getLatLonFromGeoapify("{$rsc->getAddress()}, {$rsc->getCity()}, {$rsc->getState()->value} {$rsc->getZip()} US");
if (!$res) {
$this->addFlash('warning', 'Could not retrieve latitude and longitude. Please try again.');
return $this->redirectToRoute('app_community_resource_add');
}
list($lat, $lon) = $res;
$rsc->setLat($lat);
$rsc->setLon($lon);
$this->entityManager->persist($rsc); $this->entityManager->persist($rsc);
$this->entityManager->flush(); $this->entityManager->flush();
@ -114,6 +164,18 @@ class CommunityResourceController extends AbstractController
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$res = Libs::getLatLonFromGeoapify("{$rsc->getAddress()}, {$rsc->getCity()}, {$rsc->getState()->value} {$rsc->getZip()} US");
if (!$res) {
$this->addFlash('warning', 'Could not retrieve latitude and longitude. Please try again.');
return $this->redirectToRoute('app_community_resource_edit', ['id' => $id]);
}
list($lat, $lon) = $res;
$rsc->setLat($lat);
$rsc->setLon($lon);
$this->entityManager->flush(); $this->entityManager->flush();
$this->addFlash('success', 'Resource updated successfully'); $this->addFlash('success', 'Resource updated successfully');
@ -160,4 +222,13 @@ class CommunityResourceController extends AbstractController
'Content-Transfer-Encoding' => 'binary' 'Content-Transfer-Encoding' => 'binary'
]); ]);
} }
#[Route('/api/filter-resource-by-county', name: 'app_api_filter_resource_by_county')]
public function filterResourceByCounty(Request $request): Response
{
$data = json_decode($request->getContent(), true);
$county = $data['county'];
$resources = $this->entityManager->getRepository(CommunityResource::class)->findBy(['county' => $county]);
return $this->json($resources);
}
} }

View File

@ -8,7 +8,9 @@ use App\Entity\StaffNote;
use App\Entity\Supervision; use App\Entity\Supervision;
use App\Entity\User; use App\Entity\User;
use App\Entity\UserCase; use App\Entity\UserCase;
use App\Factory\MessageFactory;
use App\Form\StaffNoteFormType; use App\Form\StaffNoteFormType;
use App\Form\SupervisorStaffNoteFormType;
use App\Libs\Breadcrumb; use App\Libs\Breadcrumb;
use App\Libs\NavList; use App\Libs\NavList;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
@ -69,10 +71,14 @@ class StaffController extends AbstractController
#[Route('/staff/my-cases', name:'app_staff_my_cases')] #[Route('/staff/my-cases', name:'app_staff_my_cases')]
public function staffMyCases(#[CurrentUser()] User $user): Response public function staffMyCases(#[CurrentUser()] User $user): Response
{ {
$this->denyAccessUnlessGranted('IS_FULLY_AUTHENTICATED'); if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user); $this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user);
$this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user); $this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user);
$sup = $this->entityManager->getRepository(Supervision::class)->findOneBy(['worker' => $user]);
$ucs = $this->entityManager->getRepository(UserCase::class)->findBy(['user' => $user]); $ucs = $this->entityManager->getRepository(UserCase::class)->findBy(['user' => $user]);
$cases = []; $cases = [];
$this->navLinks['staff_dashboard'] = 'nav-link text-dark'; $this->navLinks['staff_dashboard'] = 'nav-link text-dark';
@ -89,6 +95,7 @@ class StaffController extends AbstractController
[ [
'cases' => $cases, 'cases' => $cases,
'user' => $user, 'user' => $user,
'supervisor' => $sup->getSupervisor(),
'breadcrumbs' => [ 'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_staff_dashboard'), 'Staff Dashboard'), new Breadcrumb($this->generateUrl('app_staff_dashboard'), 'Staff Dashboard'),
new Breadcrumb('', 'Staff Cases') new Breadcrumb('', 'Staff Cases')
@ -103,7 +110,9 @@ class StaffController extends AbstractController
#[Route('/staff/{staffId}', name: 'app_staff_cases')] #[Route('/staff/{staffId}', name: 'app_staff_cases')]
public function staffCases(string $staffId, #[CurrentUser()] User $user): Response public function staffCases(string $staffId, #[CurrentUser()] User $user): Response
{ {
$this->denyAccessUnlessGranted(['ROLE_ADMIN', 'ROLE_CASE_MANAGER']); if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user); $this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user);
$this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user); $this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user);
@ -137,19 +146,23 @@ class StaffController extends AbstractController
#[Route('/staff/{staffId}/case/{caseId}/list-notes', name: 'app_staff_list_notes')] #[Route('/staff/{staffId}/case/{caseId}/list-notes', name: 'app_staff_list_notes')]
public function staffListNotes(string $staffId, string $caseId, #[CurrentUser()] User $user): Response public function staffListNotes(string $staffId, string $caseId, #[CurrentUser()] User $user): Response
{ {
$this->denyAccessUnlessGranted('IS_FULLY_AUTHENTICATED'); if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user); $this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user);
$this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user); $this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user);
$isWorker = ($staffId == $user->getId()->toString());
$staff = $this->entityManager->getRepository(User::class)->find($staffId); $staff = $this->entityManager->getRepository(User::class)->find($staffId);
$case = $this->entityManager->getRepository(MemberCase::class)->find($caseId); $case = $this->entityManager->getRepository(MemberCase::class)->find($caseId);
$staffNotes = $this->entityManager->getRepository(StaffNote::class)->findBy(['memberCase' => $case]); $staffNotes = $this->entityManager->getRepository(StaffNote::class)->getOrderedNotes($case);
return $this->render( return $this->render(
'internal/staff/notes/list-notes.html.twig', 'internal/staff/notes/list-notes.html.twig',
array_merge( array_merge(
$this->navLinks, $this->navLinks,
[ [
'isWorker' => $isWorker,
'staffId' => $staffId, 'staffId' => $staffId,
'staff' => $staff, 'staff' => $staff,
'case' => $case, 'case' => $case,
@ -175,7 +188,9 @@ class StaffController extends AbstractController
#[Route('/staff/add-note/{caseId}', name: 'app_staff_add_note')] #[Route('/staff/add-note/{caseId}', name: 'app_staff_add_note')]
public function addNote(string $caseId, #[CurrentUser()] User $user, Request $request): Response public function addNote(string $caseId, #[CurrentUser()] User $user, Request $request): Response
{ {
$this->denyAccessUnlessGranted('IS_FULLY_AUTHENTICATED'); if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user); $this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user);
$this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user); $this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user);
@ -190,10 +205,24 @@ class StaffController extends AbstractController
$note = $form->getData(); $note = $form->getData();
$note->setMemberCase($case); $note->setMemberCase($case);
/** @var Supervision $sup */
$sup = $this->entityManager->getRepository(Supervision::class)->findOneBy(['worker' => $user]);
$msg = MessageFactory::createStaffing($user, $sup->getSupervisor());
$this->entityManager->persist($msg);
$this->entityManager->persist($note); $this->entityManager->persist($note);
$this->entityManager->flush(); $this->entityManager->flush();
return $this->redirectToRoute('app_staff_list_notes', ['staffId' => $user->getId()->toHex(), 'caseId' => $caseId]); $this->addFlash('info', 'Staff note added');
return $this->redirectToRoute(
'app_staff_list_notes',
[
'staffId' => $user->getId()->toString(),
'caseId' => $caseId
]
);
} }
return $this->render( return $this->render(
@ -218,15 +247,21 @@ class StaffController extends AbstractController
#[Route('/staff/edit-note/{noteId}', name: 'app_staff_edit_note')] #[Route('/staff/edit-note/{noteId}', name: 'app_staff_edit_note')]
public function editNote(string $noteId, #[CurrentUser()] User $user, Request $request): Response public function editNote(string $noteId, #[CurrentUser()] User $user, Request $request): Response
{ {
$this->denyAccessUnlessGranted('IS_FULLY_AUTHENTICATED'); if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user); $this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user);
$this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user); $this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user);
$note = $this->entityManager->getRepository(StaffNote::class)->find($noteId); $note = $this->entityManager->getRepository(StaffNote::class)->find($noteId);
$case = $note->getMemberCase(); $case = $note->getMemberCase();
$form = $this->createForm(StaffNoteFormType::class, $note); if ($note->supervisorSignDateTime || $note->workerSignDateTime) {
$this->addFlash('error', 'This note has already been signed');
return $this->redirectToRoute('app_staff_view_note', ['noteId' => $noteId]);
}
$form = $this->createForm(StaffNoteFormType::class, $note);
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
@ -234,9 +269,157 @@ class StaffController extends AbstractController
$this->addFlash('info', 'Staff notes updated'); $this->addFlash('info', 'Staff notes updated');
$this->redirectToRoute('app_staff_list_note', ['staffId' => $user->getId()->toHex(), 'caseId' => $case->getId()->toHex()]); $this->redirectToRoute('app_staff_list_notes', ['staffId' => $user->getId()->toString(), 'caseId' => $case->getId()->toString()]);
} }
return new Response(); return $this->render(
'internal/staff/notes/edit-note.html.twig',
array_merge(
$this->navLinks,
[
'form' => $form,
'note' => $note,
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_staff_my_cases'), 'My Cases'),
new Breadcrumb($this->generateUrl('app_staff_list_notes', ['staffId' => $user->getId()->toString(), 'caseId' => $case->getId()->toString()]), 'Case Notes'),
new Breadcrumb('', 'Edit Note'),
],
'notifications' => $this->msgs,
'notificationCount' => $this->notificationCount,
]
)
);
}
#[Route('/staff/sign-my-note/{noteId}', name: 'app_staff_sign_my_note')]
public function signNote(string $noteId, #[CurrentUser()] User $user, Request $request): Response
{
if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user);
$this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user);
$note = $this->entityManager->getRepository(StaffNote::class)->find($noteId);
$case = $note->getMemberCase();
if (!$note->getSupervisorSignDateTime()) {
$this->addFlash('error', 'Your supervisor has not signed this note');
return $this->redirectToRoute('app_staff_list_notes', ['staffId' => $user->getId()->toString(), 'caseId' => $case->getId()->toString()]);
}
$form = $this->createForm(StaffNoteFormType::class, $note);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$note->setWorkerSignDateTime(new \DateTimeImmutable());
$this->entityManager->flush();
$this->addFlash('info', 'Staff notes signed and saved');
$this->redirectToRoute('app_staff_list_notes', ['staffId' => $user->getId()->toString(), 'caseId' => $case->getId()->toString()]);
}
return $this->render(
'internal/staff/notes/sign-note.html.twig',
array_merge(
$this->navLinks,
[
'form' => $form,
'note' => $note,
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_staff_my_cases'), 'My Cases'),
new Breadcrumb($this->generateUrl('app_staff_list_notes', ['staffId' => $user->getId()->toString(), 'caseId' => $case->getId()->toString()]), 'Case Notes'),
new Breadcrumb('', 'Sign Note'),
],
'notifications' => $this->msgs,
'notificationCount' => $this->notificationCount,
]
)
);
}
#[Route('/staff/sup-sign-note/{noteId}', name: 'app_staff_sign_worker_note')]
public function supSignNote(string $noteId, #[CurrentUser()] User $user, Request $request): Response
{
if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user);
$this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user);
$note = $this->entityManager->getRepository(StaffNote::class)->find($noteId);
$case = $note->getMemberCase();
$form = $this->createForm(SupervisorStaffNoteFormType::class, $note);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$note->setSupervisorSignDateTime(new \DateTimeImmutable());
/** @var UserCase $uc */
$uc = $this->entityManager->getRepository(UserCase::class)->findOneBy(['case' => $case]);
$msg = MessageFactory::createSupervisorSignStaffNote($user, $uc->getUser(), $case);
$this->entityManager->persist($msg);
$this->entityManager->flush();
$this->addFlash('info', 'Staff notes signed and saved');
$this->redirectToRoute('app_staff_list_notes', ['staffId' => $user->getId()->toString(), 'caseId' => $case->getId()->toString()]);
}
return $this->render(
'internal/staff/notes/sup-sign-note.html.twig',
array_merge(
$this->navLinks,
[
'form' => $form,
'note' => $note,
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_staff_my_cases'), 'Staff Dashboard'),
new Breadcrumb($this->generateUrl('app_staff_cases', ['staffId' => $user->getId()->toString()]), 'Cases'),
new Breadcrumb($this->generateUrl('app_staff_list_notes', ['staffId' => $user->getId()->toString(), 'caseId' => $case->getId()->toString()]), 'Case Notes'),
new Breadcrumb('', 'Sign Note'),
],
'notifications' => $this->msgs,
'notificationCount' => $this->notificationCount,
]
)
);
}
#[Route('/staff/view/{noteId}', name: 'app_staff_view_note')]
public function viewNote(string $noteId, #[CurrentUser()] User $user): Response
{
if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$this->msgs = $this->entityManager->getRepository(Messages::class)->getUnreadMessages($user);
$this->notificationCount = $this->entityManager->getRepository(Messages::class)->getUnreadMessageCount($user);
$note = $this->entityManager->getRepository(StaffNote::class)->find($noteId);
return $this->render(
'internal/staff/notes/view-note.html.twig',
array_merge(
$this->navLinks,
[
'note' => $note,
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_staff_my_cases'), 'My Cases'),
new Breadcrumb($this->generateUrl('app_staff_list_notes', ['staffId' => $user->getId()->toString(), 'caseId' => $note->getMemberCase()->getId()->toString()]), 'Case Notes'),
new Breadcrumb('', 'View Note'),
],
'notifications' => $this->msgs,
'notificationCount' => $this->notificationCount,
]
)
);
} }
} }

View File

@ -100,9 +100,15 @@ class CommunityResource
#[ORM\Column(length: 255, nullable: true)] #[ORM\Column(length: 255, nullable: true)]
private ?string $servicesAvailable = null; private ?string $servicesAvailable = null;
#[ORM\Column(type: Types::SIMPLE_ARRAY, enumType: ResourceType::class)] #[ORM\Column(type: Types::JSON, enumType: ResourceType::class)]
private array $type = []; private array $type = [];
#[ORM\Column(nullable: true)]
private ?float $lat = null;
#[ORM\Column(nullable: true)]
private ?float $lon = null;
public function __construct( public function __construct(
private DateTime $today = new DateTime('now', new DateTimeZone('America/New_York')) private DateTime $today = new DateTime('now', new DateTimeZone('America/New_York'))
) { ) {
@ -641,4 +647,28 @@ class CommunityResource
return $this; return $this;
} }
public function getLat(): ?float
{
return $this->lat;
}
public function setLat(?float $lat): static
{
$this->lat = $lat;
return $this;
}
public function getLon(): ?float
{
return $this->lon;
}
public function setLon(?float $lon): static
{
$this->lon = $lon;
return $this;
}
} }

View File

@ -31,6 +31,12 @@ class StaffNote
#[ORM\Column(length: 500, nullable: true)] #[ORM\Column(length: 500, nullable: true)]
private ?string $recommendations = null; private ?string $recommendations = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $workerSignDatetime = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $supervisorSignDateTime = null;
public function getId(): ?int public function getId(): ?int
{ {
return $this->id; return $this->id;
@ -98,4 +104,28 @@ class StaffNote
return $this; return $this;
} }
public function getWorkerSignDatetime(): ?\DateTimeInterface
{
return $this->workerSignDatetime;
}
public function setWorkerSignDatetime(?\DateTimeInterface $workerSignDatetime): static
{
$this->workerSignDatetime = $workerSignDatetime;
return $this;
}
public function getSupervisorSignDateTime(): ?\DateTimeInterface
{
return $this->supervisorSignDateTime;
}
public function setSupervisorSignDateTime(?\DateTimeInterface $supervisorSignDateTime): static
{
$this->supervisorSignDateTime = $supervisorSignDateTime;
return $this;
}
} }

View File

@ -121,4 +121,18 @@ class MessageFactory
return $msg; return $msg;
} }
public static function createSupervisorSignStaffNote(User $sender, User $recipient, MemberCase $case): Messages
{
$msg = new Messages();
$msg->setSender($sender)
->setRecipient($recipient)
->setSent(new DateTimeImmutable())
->setType(MessageType::STAFFING)
->setTitle('Staff Note Signed')
->setMessage("Supervisor signed note for {$case->getCaseName()}")
;
return $msg;
}
} }

View File

@ -25,7 +25,6 @@ class StaffNoteFormType extends AbstractType
'multiple' => true, 'multiple' => true,
]) ])
->add('note', TextareaType::class) ->add('note', TextareaType::class)
->add('recommendations')
; ;
} }

View File

@ -0,0 +1,43 @@
<?php
namespace App\Form;
use App\Entity\MemberCase;
use App\Entity\StaffNote;
use App\Enums\ReferralServiceType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EnumType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class SupervisorStaffNoteFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('date', null, [
'widget' => 'single_text',
'disabled' => 'disabled'
])
->add('servicesProvided', EnumType::class, [
'class' => ReferralServiceType::class,
'expanded' => true,
'multiple' => true,
'disabled' => 'disabled'
])
->add('note', TextareaType::class, [
'disabled' => 'disabled'
])
->add('recommendations')
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => StaffNote::class,
]);
}
}

27
src/Libs/Libs.php Normal file
View File

@ -0,0 +1,27 @@
<?php
namespace App\Libs;
class Libs
{
public static function getLatLonFromGeoapify($address): ?array
{
$address = urlencode($address);
$url = "https://api.geoapify.com/v1/geocode/search?text={$address}&format=json&apiKey={$_ENV['GEOAPIFY_API_KEY']}";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$result = curl_exec($ch);
curl_close($ch);
$result = json_decode($result, true);
if (isset($result['results'][0]['lat']) && isset($result['results'][0]['lon'])) {
$lat = $result['results'][0]['lat'];
$lon = $result['results'][0]['lon'];
return [$lat, $lon];
}
return null;
}
}

View File

@ -2,6 +2,7 @@
namespace App\Repository; namespace App\Repository;
use App\Entity\MemberCase;
use App\Entity\StaffNote; use App\Entity\StaffNote;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
@ -16,6 +17,16 @@ class StaffNoteRepository extends ServiceEntityRepository
parent::__construct($registry, StaffNote::class); parent::__construct($registry, StaffNote::class);
} }
public function getOrderedNotes(MemberCase $case): array
{
return $this->createQueryBuilder('s')
->andWhere('s.memberCase = :case')
->setParameter('case', $case->getId()->toBinary())
->orderBy('s.date', 'DESC')
->getQuery()
->getResult();
}
// /** // /**
// * @return StaffNote[] Returns an array of StaffNote objects // * @return StaffNote[] Returns an array of StaffNote objects
// */ // */

View File

@ -11,8 +11,8 @@
</title> </title>
<!-- Simple CSS <!-- Simple CSS
<link <link
rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">--> rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">-->
<!-- Fonts and icons --> <!-- Fonts and icons -->
<link <link
@ -28,34 +28,36 @@
rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0"/> rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0,0"/>
<!-- CSS Files --> <!-- CSS Files -->
<link id="pagestyle" href="{{ asset('css/material-dashboard.css') }}?v=3.2.0" rel="stylesheet"/> {% block stylesheets %}{% endblock %} <link id="pagestyle" href="{{ asset('css/material-dashboard.css') }}?v=3.2.0" rel="stylesheet"/> {% block stylesheets %}{% endblock %}
</head> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
</head>
<body class="bg-gray-200"> {% block body %}{% endblock %} <body class="bg-gray-200"> {% block body %}{% endblock %}
{% block javascripts %} {% block javascripts %}
<script src="{{ asset('js/core/popper.min.js') }}"></script> <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
<script src="{{ asset('js/core/bootstrap.min.js') }}"></script> <script src="{{ asset('js/core/popper.min.js') }}"></script>
<script src="{{ asset('js/plugins/perfect-scrollbar.min.js') }}"></script> <script src="{{ asset('js/core/bootstrap.min.js') }}"></script>
<script src="{{ asset('js/plugins/smooth-scrollbar.min.js') }}"></script> <script src="{{ asset('js/plugins/perfect-scrollbar.min.js') }}"></script>
<script> <script src="{{ asset('js/plugins/smooth-scrollbar.min.js') }}"></script>
var win = navigator.platform.indexOf('Win') > -1; <script>
var win = navigator.platform.indexOf('Win') > -1;
if (win && document.querySelector('#sidenav-scrollbar')) { if (win && document.querySelector('#sidenav-scrollbar')) {
var options = { var options = {
damping: '0.5' damping: '0.5'
} }
Scrollbar.init(document.querySelector('#sidenav-scrollbar'), options); Scrollbar.init(document.querySelector('#sidenav-scrollbar'), options);
} }
</script> </script>
<!-- Github buttons --> <!-- Github buttons -->
<script async defer src="https://buttons.github.io/buttons.js"></script> <script async defer src="https://buttons.github.io/buttons.js"></script>
<!-- Control Center for Material Dashboard: parallax effects, scripts for the example pages etc --> <!-- Control Center for Material Dashboard: parallax effects, scripts for the example pages etc -->
<script src="{{ asset('js/material-dashboard.js') }}?v=3.2.0"></script> <script src="{{ asset('js/material-dashboard.js') }}?v=3.2.0"></script>
<script src='{{ asset('js/script.js') }}'></script> <script src='{{ asset('js/script.js') }}'></script>
{% block importmap %} {% block importmap %}
{{ importmap('app') }} {{ importmap('app') }}
{% endblock %}
{% endblock %} {% endblock %}
</body> {% endblock %}
</html> </body>
</html>

View File

@ -20,6 +20,7 @@
<h6 class="text-white text-capitalize ps-3">Free/Low-cost Community Resources</h6> <h6 class="text-white text-capitalize ps-3">Free/Low-cost Community Resources</h6>
</div> </div>
<div> <div>
<button type='button' class='btn btn-block btn-light mb-3' onclick="window.open('{{ path('app_community_resource_map') }}', '_self')">Map</button>
<button type="button" class="btn btn-block btn-light mb-3" onclick="window.open('{{ path('app_community_resource_add') }}', '_self')">Add Resource</button> <button type="button" class="btn btn-block btn-light mb-3" onclick="window.open('{{ path('app_community_resource_add') }}', '_self')">Add Resource</button>
</div> </div>
</div> </div>
@ -27,7 +28,7 @@
<div class="card-body px-0 pb-2"> <div class="card-body px-0 pb-2">
<div> <div>
Filters: Filters:
<select onchange='filterResourceByCounty(this.value)'> <select onchange='filterResourceByCounty()' id='countyList'>
<option value=''></option> <option value=''></option>
{% for c in enum('App\\Enums\\County').cases() %} {% for c in enum('App\\Enums\\County').cases() %}

View File

@ -0,0 +1,17 @@
{% extends 'base.html.twig' %}
{% block title %}Community Resources
{% endblock %}
{% block body %}
{% set today = date("now", "America/Indiana/Indianapolis") %}
{{ block('nav', 'internal/libs/nav.html.twig') }}
<main class="main-content position-relative max-height-vh-100 h-100 border-radius-lg ">
{{ block('topnav', 'internal/libs/top-nav.html.twig') }}
<div class="container-fluid py-2">
{{ ux_map(map, {style: 'height: 600px', 'data-controller': 'my-map'}) }}
</div>
</main>
{% endblock %}

View File

@ -46,23 +46,23 @@
</li> </li>
{% endif %} {% endif %}
<li class="nav-item mt-3">
<h6 class="ps-4 ms-2 text-uppercase text-xs text-dark font-weight-bolder opacity-5">Staffing pages</h6>
</li>
{% if is_granted('ROLE_CASE_MANAGER') or is_granted('ROLE_ADMIN') %} {% if is_granted('ROLE_CASE_MANAGER') or is_granted('ROLE_ADMIN') %}
<li class="nav-item mt-3">
<h6 class="ps-4 ms-2 text-uppercase text-xs text-dark font-weight-bolder opacity-5">Staffing pages</h6>
</li>
<li class='nav-item'> <li class='nav-item'>
<a class='{{ staff_dashboard }}' href='{{ path('app_staff_dashboard') }}'> <a class='{{ staff_dashboard }}' href='{{ path('app_staff_dashboard') }}'>
<i class='material-symbols-rounded opacity-5'>dashboard</i> <i class='material-symbols-rounded opacity-5'>dashboard</i>
<span class='nav-link-text ms-1'>Staff Dashboard</span> <span class='nav-link-text ms-1'>Staff Dashboard</span>
</a> </a>
</li> </li>
<li class='nav-item'>
<a class='{{ staff_notes }}' href='{{ path('app_staff_my_cases') }}'>
<i class='material-symbols-rounded opacity-5'></i>
<span class='nav-link-text ms-1'>Staff My Cases</span>
</a>
</li>
{% endif %} {% endif %}
<li class='nav-item'>
<a class='{{ staff_notes }}' href='{{ path('app_staff_my_cases') }}'>
<i class='material-symbols-rounded opacity-5'>supervisor_account</i>
<span class='nav-link-text ms-1'>Staff My Cases</span>
</a>
</li>
<li class="nav-item mt-3"> <li class="nav-item mt-3">
<h6 class="ps-4 ms-2 text-uppercase text-xs text-dark font-weight-bolder opacity-5">User pages</h6> <h6 class="ps-4 ms-2 text-uppercase text-xs text-dark font-weight-bolder opacity-5">User pages</h6>

View File

@ -9,7 +9,11 @@
<div class='row'> <div class='row'>
<div class='ms-3'> <div class='ms-3'>
<h3 class='mb-0 h4 font-weight-bolder'>My Cases</h3> <h3 class='mb-0 h4 font-weight-bolder'>My Cases</h3>
<p class='mb-4'></p> <p class='mb-4'>
{{ supervisor.name }}<br/>
<a href='mailto:{{ supervisor.email }}'>{{ supervisor.email }}</a><br/>
<a href='tel:'></a>
</p>
</div> </div>
{% for c in cases %} {% for c in cases %}
<div class='col-xl-3 col-sm-6 mb-xl-0 mb-4'> <div class='col-xl-3 col-sm-6 mb-xl-0 mb-4'>

View File

@ -20,37 +20,32 @@
{{ form_start(form) }} {{ form_start(form) }}
<div class="row"> <div class="row">
<div class='col'> <div class='col'>
<div class='input-group input-group-outline mb-3'> <div class='input-group input-group-outline mb-3'>
<label for='note_form_date'></label> <label for='note_form_date'></label>
<input type='date' name='{{ field_name(form.date) }}' id='note_form_date' class='form-control'/> <input type='date' name='{{ field_name(form.date) }}' id='note_form_date' class='form-control'/>
</div> </div>
<div class='input-group input-group-outline mb-3'> <div class='input-group input-group-outline mb-3'>
{{ form_row(form.servicesProvided) }} {{ form_row(form.servicesProvided) }}
</div> </div>
</div>
<div class='input-group input-group-outline mb-3'> <div class='col'>
<label for='note_form_recommendation' class='form-label'>Recommendation</label> <div class='input-group input-group-outline mb-3'>
<input type='text' name='{{ field_name(form.recommendations) }}' id='note_form_recommendation' class='form-control'/> <textarea name='{{ field_name(form.note) }}' id='note_form_note' class='form-control' placeholder='Note' style='width:100%;height:250px;'></textarea>
</div> </div>
</div> </div>
</div>
<div class='col'>
<div class='input-group input-group-outline mb-3'>
<textarea name='{{ field_name(form.note) }}' id='note_form_note' class='form-control' placeholder='Note' style='width:100%;height:200px;'></textarea>
</div>
</div>
</div>
<div class='row'> <div class='row'>
<div class="text-center"> <div class="text-center">
<button type="submit" class="btn btn-lg bg-gradient-dark btn-lg w-100 mt-4 mb-0">Save Staff Note</button> <button type="submit" class="btn btn-lg bg-gradient-dark btn-lg w-100 mt-4 mb-0">Save Staff Note</button>
</div> </div>
</div> </div>
{{ form_end(form) }} {{ form_end(form) }}
</div> </div>
</div> </div>
</div> </div>
</section> </section>
</main> </main>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,51 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ block('nav', 'internal/libs/nav.html.twig') }}
<main class="main-content position-relative max-height-vh-100 h-100 border-radius-lg ">
{{ block('topnav', 'internal/libs/top-nav.html.twig') }}
<section>
<div class="card card-plain">
<div class="card-header">
<h4 class="font-weight-bolder">Case Info</h4>
<p class="mb-0"></p>
</div>
<div class="card-body">
<div class="container">
{{ form_errors(form) }}
{{ form_start(form) }}
<div class="row">
<div class='col'>
<div class='input-group input-group-outline mb-3'>
<label for='note_form_date'></label>
<input type='date' name='{{ field_name(form.date) }}' value='{{ field_value(form.date) }}' id='note_form_date' class='form-control'/>
</div>
<div class='input-group input-group-outline mb-3'>
{{ form_row(form.servicesProvided) }}
</div>
</div>
<div class='col'>
<div class='input-group input-group-outline mb-3'>
<textarea name='{{ field_name(form.note) }}' id='note_form_note' class='form-control' placeholder='Note' style='width:100%;height:250px;'>{{ field_value(form.note) }}</textarea>
</div>
</div>
</div>
<div class='row'>
<div class="text-center">
<button type="submit" class="btn btn-lg bg-gradient-dark btn-lg w-100 mt-4 mb-0">Save Staff Note</button>
</div>
</div>
{{ form_end(form) }}
</div>
</div>
</div>
</section>
</main>
{% endblock %}

View File

@ -16,9 +16,9 @@
<h6 class="text-white text-capitalize ps-3">{{ case.caseName }}</h6> <h6 class="text-white text-capitalize ps-3">{{ case.caseName }}</h6>
</div> </div>
{% if app.user.id == staffId %} {% if app.user.id == staffId %}
<div> <div>
<button type="button" class="btn btn-block btn-light mb-3" onclick="window.open('{{ path('app_staff_add_note', {caseId: case.id}) }}', '_self')">Add Staff Note</button> <button type="button" class="btn btn-block btn-light mb-3" onclick="window.open('{{ path('app_staff_add_note', {caseId: case.id}) }}', '_self')">Add Staff Note</button>
</div> </div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
@ -28,6 +28,8 @@
<thead> <thead>
<tr> <tr>
<th class="text-uppercase text-secondary text-xxs font-weight-bolder opacity-7">Date</th> <th class="text-uppercase text-secondary text-xxs font-weight-bolder opacity-7">Date</th>
<th class='text-uppercase text-secondary text-xxs font-weight-bolder opacity-7'>Supervisor Signed</th>
<th class='text-uppercase text-secondary text-xxs font-weight-bolder opacity-7'>Signed</th>
<th class="text-secondary opacity-7"></th> <th class="text-secondary opacity-7"></th>
</tr> </tr>
</thead> </thead>
@ -41,10 +43,40 @@
</div> </div>
</div> </div>
</td> </td>
<td>
{% if n.supervisorSignDateTime %}
{{ n.supervisorSignDateTime|date('F j, Y h:i a') }}
{% endif %}
</td>
<td>
{% if n.workerSignDatetime %}
{{ n.workerSignDatetime|date('F j, Y h:i a') }}
{% endif %}
</td>
<td class='align-right'> <td class='align-right'>
<a href='{{ path('app_staff_edit_note', {noteId: n.id}) }}' title='Edit Note'> {% if isWorker and not n.workerSignDatetime %}
<i class='material-symbols-rounded opacity-5'>edit</i> <a href='{{ path('app_staff_edit_note', {noteId: n.id}) }}' title='Edit Note'>
</a> <i class='material-symbols-rounded opacity-5'>edit</i>
</a>
<a href='{{ path('app_staff_sign_my_note', {noteId: n.id}) }}' title='Sign Note'>
<i class='material-symbols-rounded opacity-5'>draw</i>
</a>
{% endif %}
{% if isWorker and n.workerSignDatetime %}
<a href='{{ path('app_staff_view_note', {noteId: n.id}) }}' title='View Note'>
<i class='material-symbols-rounded opacity-5'>visibility</i>
</a>
{% endif %}
{% if not isWorker and not n.supervisorSignDateTime %}
<a href='{{ path('app_staff_sign_worker_note', {noteId: n.id}) }}' title='Sign Note'>
<i class='material-symbols-rounded opacity-5'>draw</i>
</a>
{% endif %}
{% if not isWorker and n.supervisorSignDateTime %}
<a href='{{ path('app_staff_view_note', {noteId: n.id}) }}' title='View Note'>
<i class='material-symbols-rounded opacity-5'>visibility</i>
</a>
{% endif %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -0,0 +1,62 @@
{% extends 'base.html.twig' %}
{% block stylesheet %}
<style>
@import url('https://fonts.googleapis.com/css2?family=Herr+Von+Muellerhoff &display=swap');
.herr-von-muellerhoff-regular {
font-family: "Herr Von Muellerhoff", cursive;
font-weight: 400;
font-style: normal;
}
</style>
{% endblock %}
{% block body %}
{{ block('nav', 'internal/libs/nav.html.twig') }}
<main class="main-content position-relative max-height-vh-100 h-100 border-radius-lg ">
{{ block('topnav', 'internal/libs/top-nav.html.twig') }}
<section>
<div class="card card-plain">
<div class="card-header">
<h4 class="font-weight-bolder">Staff Case Note</h4>
<p class="mb-0"></p>
</div>
<div class="card-body">
<div class="container">
{{ form_start(form) }}
{{ form_errors(form) }}
<div class="row">
<div class='col'>
<div class='input-group input-group-outline mb-3'>
<label for='note_form_date'></label>
<input type='date' name='{{ field_name(form.date) }}' value='{{ field_value(form.date) }}' id='note_form_date' class='form-control'/>
</div>
<div class='input-group input-group-outline mb-3'>
{{ form_row(form.servicesProvided) }}
</div>
</div>
<div class='col'>
<div class='input-group input-group-outline mb-3'>
<textarea name='{{ field_name(form.note) }}' id='note_form_note' class='form-control' placeholder='Note' style='width:100%;height:200px;'>{{ field_value(form.note) }}</textarea>
</div>
</div>
</div>
<div class='row'>
<div class="text-center">
<button type="submit" class="btn btn-lg bg-gradient-dark btn-lg w-100 mt-4 mb-0">Save and Sign Note</button>
</div>
</div>
{{ form_end(form) }}
</div>
</div>
</div>
</section>
</main>
{% endblock %}

View File

@ -0,0 +1,67 @@
{% extends 'base.html.twig' %}
{% block stylesheet %}
<style>
@import url('https://fonts.googleapis.com/css2?family=Herr+Von+Muellerhoff &display=swap');
.herr-von-muellerhoff-regular {
font-family: "Herr Von Muellerhoff", cursive;
font-weight: 400;
font-style: normal;
}
</style>
{% endblock %}
{% block body %}
{{ block('nav', 'internal/libs/nav.html.twig') }}
<main class="main-content position-relative max-height-vh-100 h-100 border-radius-lg ">
{{ block('topnav', 'internal/libs/top-nav.html.twig') }}
<section>
<div class="card card-plain">
<div class="card-header">
<h4 class="font-weight-bolder">Case Info</h4>
<p class="mb-0"></p>
</div>
<div class="card-body">
<div class="container">
{{ form_start(form) }}
{{ form_errors(form) }}
<div class="row">
<div class='col'>
<div class='input-group input-group-outline mb-3'>
<label for='note_form_date'></label>
<input type='date' name='{{ field_name(form.date) }}' value='{{ field_value(form.date) }}' disabled='disabled' id='note_form_date' class='form-control'/>
</div>
<div class='input-group input-group-outline mb-3'>
<label for='note_form_recommendation' class='form-label'>Recommendation</label>
<input type='text' name='{{ field_name(form.recommendations) }}' value='{{ field_value(form.recommendations) }}' id='note_form_recommendation' class='form-control'/>
</div>
<div class='input-group input-group-outline mb-3'>
{{ form_row(form.servicesProvided) }}
</div>
</div>
<div class='col'>
<div class='input-group input-group-outline mb-3'>
<textarea name='{{ field_name(form.note) }}' disabled='disabled' id='note_form_note' class='form-control' placeholder='Note' style='width:100%;height:200px;'>{{ field_value(form.note) }}</textarea>
</div>
</div>
</div>
<div class='row'>
<div class="text-center">
<button type="submit" class="btn btn-lg bg-gradient-dark btn-lg w-100 mt-4 mb-0">Save and Sign Note</button>
</div>
</div>
{{ form_end(form) }}
</div>
</div>
</div>
</section>
</main>
{% endblock %}

View File

@ -0,0 +1,55 @@
{% extends 'base.html.twig' %}
{% block body %}
{{ block('nav', 'internal/libs/nav.html.twig') }}
<main class="main-content position-relative max-height-vh-100 h-100 border-radius-lg ">
{{ block('topnav', 'internal/libs/top-nav.html.twig') }}
<section>
<div class="card card-plain">
<div class="card-header">
<h4 class="font-weight-bolder">Case Info</h4>
<p class="mb-0"></p>
</div>
<div class="card-body">
<div class="container">
<div class="row">
<div class='col'>
<div class='input-group input-group-outline mb-3'>
<p>Supervisor Signed:
{{ note.supervisorSignDateTime|date("F j, Y h:i a") }}</p>
<p>Case Worker Signed:
{{ note.workerSignDatetime|date("F j, Y h:i a") }}</p>
</div>
<div class='input-group input-group-outline mb-3'>
<label for='note_form_date'></label>
<input type='date' name='date' id='note_form_date' value='{{ note.date|date("Y-m-d") }}' disabled="disabled" class='form-control'/>
</div>
<div class='input-group input-group-outline mb-3 is-filled'>
<label for='note_form_recommendation' class='form-label'>Recommendations</label>
<input type='text' name='recommendation' id='note_form_recommendation' value='{{ note.recommendations }}' disabled='disabled' class='form-control'/>
</div>
</div>
<div class='col'>
<div class='input-group input-group-outline mb-3'>
<textarea name='note' disabled='disabled' id='note_form_note' class='form-control' style='width:100%;height:250px;'>{{ note.note }}</textarea>
</div>
</div>
</div>
<div class='row'>
<div class="text-center">
<button type="button" class="btn btn-lg bg-gradient-dark btn-lg w-100 mt-4 mb-0" onclick="history.go(-1)">Back</button>
</div>
</div>
</div>
</div>
</div>
</section>
</main>
{% endblock %}