Compare commits

...

253 Commits

Author SHA1 Message Date
c9cf8d7e0a up: various twig templates
* various twig updates
2025-02-10 16:18:53 -05:00
b828333222 fix: twig note templates
* fix edit notes and and member present
* refactor enum moving process
2025-02-10 15:10:25 -05:00
607ca79c4d up: various
* various minor update
2025-02-10 15:08:28 -05:00
0ebd90a03b up: twig company-info
* add vendorId twig template form element
2025-02-10 15:05:56 -05:00
24784bb1bb add: twig case
* add case rate to twig template forms
2025-02-10 15:04:43 -05:00
e3380bab2f up: UserChecker
* Rename user class
2025-02-10 15:03:02 -05:00
2cd4c68baf fix: MemberRepository
* Fix getting selected members from a note
2025-02-10 15:00:10 -05:00
52f835bbda fix: *NoteFormType
* Fix member selection
2025-02-10 14:59:13 -05:00
680b7ab9bd up: MemberCaseFormType
* Add rate property form element
2025-02-10 14:58:11 -05:00
4f6a80eade up: MemberCaseFormType
* Add vendorId property
2025-02-10 14:57:33 -05:00
53d9350cb8 up: MemberCase
* Add rate integer property
2025-02-10 14:54:45 -05:00
428304e5af up: Company
* add vendorId property and methods, may need to add more for reporting data
2025-02-09 18:16:14 -05:00
c4d1a33272 up: VisitNote & StandardNote
* couple minor changes
2025-02-09 18:15:21 -05:00
4fd42970ac up: Member
* add checked property and setId method to support note editing and retrieval and display of form parameters
2025-02-09 18:14:53 -05:00
1fd72d95e0 ref: MessageController
* move message controller to new path, forgot to update namespace
2025-02-09 18:14:01 -05:00
74ad66496e add: DefaultController
* add up method for connection checking
2025-02-09 18:13:32 -05:00
8851c4f6e8 ref: AjaxController
* refactor for readability
2025-02-09 18:13:00 -05:00
51ea4e2311 up: ReferralController
* remove $this->msgs and just call Libs::getMessages method
2025-02-09 18:12:36 -05:00
4859aa23b8 up: NoteController
* add error if user doesn't select referral when trying to add new note
* Finalize note editing
2025-02-09 18:11:48 -05:00
e601727514 sec: AdminController
* set initial password change date to epoch when creating new account
2025-02-09 18:10:14 -05:00
b54e2a51f9 ref: security.yaml
* update entity path after moving entities around
2025-02-09 18:09:11 -05:00
d51c67db3d up: notes.js
* Convert duration to hours/units
* Move calcTime method here
2025-02-09 18:08:32 -05:00
1cfc4c7355 rm: itinerary.js
* remove arrival because it's unnecessary
2025-02-09 18:06:42 -05:00
8e85405426 upd: CaseController
* remove assignCaseDocument method in favor of Member Document assignment
2025-01-28 21:02:20 -05:00
9887889ecb ref: Repositories
* Refactor all files
2025-01-28 20:59:14 -05:00
593958cc68 ref: Libs
* Refactor files
* Move autocompleteAddress method to GeoapifyController
2025-01-28 20:58:47 -05:00
528827868b upd: Forms
* Move classes
2025-01-28 20:54:50 -05:00
af6ebbb1b2 mv: Factories
* move files
2025-01-28 20:48:41 -05:00
e08e23d647 mv: Enums
* Move enums
2025-01-28 20:48:00 -05:00
bcc32bf445 mv: Refactor
* Move entities for organization
2025-01-28 20:47:26 -05:00
ee2fce4c41 upd: DataFixtures
* Refactor after moving files
2025-01-28 20:46:38 -05:00
13aaaae34c mv: All Controllers
* Move all controllers to sub-directories for organization
2025-01-28 20:43:23 -05:00
fc9ebbd327 upd: importmap
* add moment library
2025-01-24 11:20:13 -05:00
4cddccdf6e upd: twig nav
* remove case notes nav in favor of navigating through case data
* rename Case Addresses to Addresses
2025-01-24 11:19:06 -05:00
3d786f1f16 upd: twig list-notes
* correct link for adding a new note
* remove display of present members
2025-01-24 11:16:25 -05:00
e5f09bd8cc upd: Libs
Permissions checking
* Add checkPermissions method to check the permissions of the user to the case to make sure they have permissions to add or edit.
2025-01-24 10:35:46 -05:00
77d90ed691 fix: NoteForms
* change members field to unmapped
2025-01-24 10:34:12 -05:00
0d69b51ff9 upd: CommunityResource
* Add method to convert class to Location object
2025-01-24 10:19:43 -05:00
df29fd0d99 fix: NoteController
Save members
* get note members working, still need to setup editing
2025-01-24 10:18:56 -05:00
09ae2756c2 upd: ItineraryController
* remove unnecessary use statements
2025-01-24 10:17:43 -05:00
520409b0b4 fix: CaseController
* add permission validation
2025-01-24 10:15:49 -05:00
fe622ef794 upd: twig edit-members
add member documents
2025-01-22 21:32:58 -05:00
0844b3fc58 upd: MemberDocumentRepository
Remove
* remove unsigned documents from repository for member to sign
2025-01-22 21:32:26 -05:00
6468e77445 upd: User
vCard profile
* Add profile image to vCard
2025-01-22 21:31:36 -05:00
2e41c1ed83 fix: CompanyDocument
Add Property
* add selected property to support edit-member functionality
2025-01-22 21:28:27 -05:00
6ecb76a829 fix: MemberController
member editting
* Add documents
* Cleanup
2025-01-22 21:20:24 -05:00
1fa3843b50 fix: remove class permission requirement 2025-01-22 21:02:30 -05:00
e376dadb4b add: composer
* add phpstan library and require extensions
2025-01-21 14:46:35 -05:00
b990ea55cb fix: twig
* couple display fixes
2025-01-21 14:46:03 -05:00
67d83a1f98 add: twig nav
* add company directory link
2025-01-21 14:44:39 -05:00
79db6b2ec9 fix: twig add-member
* add checkboxes for each company document
2025-01-21 14:43:55 -05:00
0c5fa617ad fix: twig list-users
* fix display of user profile
* add text muting if user is inactive
2025-01-21 14:43:20 -05:00
6effcba396 fix: twig edit-user
* fix background image display
* fix display for work and personal phone numbers
* add active checkbox
* fix displays for role checkboxes
2025-01-21 14:41:49 -05:00
43e6811928 fix: twig users
Fix user background image that displays left of the form
2025-01-21 14:40:01 -05:00
705d7330b0 add: twig company-info
Add new display
2025-01-21 14:38:49 -05:00
7bc73345b0 fix: twig couple files
* fix referralType display after converting to enum
2025-01-21 14:38:12 -05:00
610cccc191 fix: twig assign-case
* add number of cases to user list
2025-01-21 14:36:46 -05:00
a47a5e8adb fix: twig add-case
* fix display with admit and close dates
* convert referralType to use enum
* fix display for case level, referral source & 2, county
* remove case documents checkboxes
2025-01-21 14:35:53 -05:00
81838608b3 add: NavList
Add company_directory field
2025-01-21 14:32:32 -05:00
d39942eced fix: MemberCase
Migration for CaseDocuments to MemberDocuments
Convert referralType field to use ReferralType Enum
2025-01-21 14:32:04 -05:00
cdacfd918a fix: MessageFactory
Add link parameter to createNewCase method
2025-01-21 14:30:17 -05:00
922852f211 fix: User
various updates
* remove unnecessary caseWorker, caseManager, therapist, su properties
* Removed retrieveUnreadNotifications method that was just a stub
* convert "is..." methods to check for present roles
* update getJobs method with above logic
* add generateVCard method to support company directory
2025-01-21 14:29:31 -05:00
224a5cd243 add: MemberDocument
Add MemberDocument class and assoc repo
2025-01-21 14:25:00 -05:00
6d8fbd5bb8 fix: MemberCase
ReferralType
* Convert ReferralType in class to an Enum
2025-01-21 14:24:11 -05:00
82ee30a724 add: CompanyDocument
Add class
* Add CompanyDocument class, associated repo and twig files
2025-01-21 14:23:14 -05:00
e13dc0bf66 fix: MemberController
MemberDocument migration
* Migrate CaseDocument to MemberDocument
* Setup assigning a document to a case member when creating member
* Still need to fix member edit
2025-01-21 14:20:57 -05:00
844209d3e3 commit gitmessage template 2025-01-21 14:18:06 -05:00
001a674f6f fix: DocumentController
move case documents to member documents
first draft of signing
2025-01-21 14:13:19 -05:00
caeb15f05b add: CompanyController
Add company directory method
2025-01-21 14:11:40 -05:00
2af4b8e04e fix: CaseController
migrate documents to MemberController
add link to new case message
2025-01-21 14:09:21 -05:00
c04e255476 fix: AdminController
ensure new users are active
fix role assignments and remove unnecessary fields
fix supervision assignment to update the record instead of deleting
2025-01-21 14:08:12 -05:00
2e77baae1b Add UserChecker to check for expired passwords, ensure users have active accounts 2025-01-21 02:07:50 +00:00
d74e10803c Add UserChecker to check for expired passwords, ensure users have active accounts 2025-01-21 02:04:29 +00:00
3d67d74242 added active and lastLogin properties 2025-01-13 22:17:22 +00:00
c2608a17cf added method to update the lastlogin so we can track how long it's been since a user last logged in. 2025-01-13 22:12:12 +00:00
1cb6bedb5c add docs for the case 2025-01-11 22:30:54 -05:00
74e811e950 add docs for the case 2025-01-11 22:03:30 -05:00
b7c0b3de6b add work and personal phone to form 2025-01-11 21:57:45 -05:00
458ba42644 couple updates 2025-01-10 15:09:44 +00:00
6687dc1401 add signature_pad and tinymce libraries 2025-01-10 15:09:01 +00:00
dc3fec7eff add company logo to form 2025-01-10 15:08:31 +00:00
acee114ccf add link to company documents if in company editor and replace links with path calls to route name 2025-01-10 15:07:59 +00:00
5f0ce69a47 remove notifcationCount variable and limit displayed notifications to 5 2025-01-10 15:06:03 +00:00
d2f8bc7cbf use company logo if available and add link to company data 2025-01-10 15:05:22 +00:00
b7b0c8e6c4 add block for assigning documents to a case, use company timezone, update anchor tag class 2025-01-10 15:03:53 +00:00
722954d0d0 remove message returning limit 2025-01-10 14:56:08 +00:00
57e002916c fix error 2025-01-10 14:55:43 +00:00
178f44fd2d add methods to get travel info 2025-01-10 14:55:14 +00:00
7b4da30342 add default const to simplify setting and resetting the list 2025-01-10 14:54:22 +00:00
03cbbc0db6 add formatPhone and getMessages methods. Also, add method to autocomplete addresses 2025-01-10 14:53:33 +00:00
f454888a6f add company form for updating the company 2025-01-10 14:51:44 +00:00
dce5dcab2f add document controller for document actions 2025-01-10 14:50:03 +00:00
75cffad2ea add company controller for company actions 2025-01-10 14:49:08 +00:00
cd8cbcf6ba add documentextras enum for documntation creation 2025-01-10 14:47:55 +00:00
6956256341 add signature block 2025-01-10 14:47:17 +00:00
42fcb7b2f5 add company logo 2025-01-10 14:46:35 +00:00
351cc7c3ac add infowindow method for mapping, convert datetime creation to use company timezone 2025-01-10 14:46:19 +00:00
e1e4c12801 add InfoWindow data methods for mapping 2025-01-10 14:44:59 +00:00
6260b13df0 convert datetime to use company timezone 2025-01-10 14:39:31 +00:00
02fcb0cc54 remove notificationCount, convert to use Libs::getMessages method, change datetime creation to use company timezone 2025-01-10 13:33:33 +00:00
2d7b7e6d12 remove notificationCount, convert to Libs::getMessages method, change datetime creation to add company timezone, remove CaseController::showCaseNotes 2025-01-10 12:44:37 +00:00
604f693c45 add company timezone 2025-01-10 12:37:16 +00:00
be80563038 add css to remove underlines in anchor tags 2025-01-10 12:36:14 +00:00
04d5e88820 javascript for various functions 2025-01-10 12:34:49 +00:00
d85c1571e7 add update for personal and work phone number 2025-01-05 06:22:29 +00:00
adcd02ff2b add modal to send message to supervisor and contact info for supervisor 2025-01-05 06:20:38 +00:00
ec487ed1ac add icon and user profile image for message type and sender 2025-01-05 06:17:37 +00:00
83a886c134 add repositories 2025-01-05 06:13:39 +00:00
43bff55192 add method to filter notes 2025-01-05 06:11:35 +00:00
2031165afc add method to format phones 2025-01-05 06:10:22 +00:00
f14a4fa67c add staff_note enum type 2025-01-05 06:10:00 +00:00
f0853bfcb2 add connector class for notes and members 2025-01-05 06:09:29 +00:00
980affbfbb add personal and work phone 2025-01-05 06:08:02 +00:00
f9608bce18 add jsonSerialize 2025-01-05 06:07:46 +00:00
c78698ace4 reconfigure 2025-01-05 06:04:21 +00:00
91723ed9be reconfigure 2025-01-05 06:03:42 +00:00
758a439187 convert list-notes to not show anything by default but have a few filter fields to display what is needed, change add notes to use different member collection and tables, add filter method 2025-01-05 06:00:40 +00:00
6dc478d0b3 add exclusion for uploads folder 2025-01-05 05:56:57 +00:00
478cb006b4 for vich_uploader 2025-01-05 05:56:34 +00:00
5b3bb9f14c add mileage_rate .env variable 2025-01-05 05:56:08 +00:00
d5b3a56e0f add firewall path for uploads/user_images 2025-01-05 05:55:39 +00:00
ca379711e2 add vich_uploader config 2025-01-05 05:54:51 +00:00
c6d4a871fa add slugifier api for profile image uploading 2025-01-03 15:38:33 +00:00
9f23dfa0eb add chartjs to importmap 2025-01-03 15:37:35 +00:00
f12f9dda12 move stylesheets block and add page_css block 2025-01-03 15:36:37 +00:00
b2972fec3e update to use actual gradient fill color for flash messages 2025-01-03 15:35:41 +00:00
18c7c33ffb remove documentation footer button 2025-01-03 15:34:41 +00:00
68236e1571 add distance measurement 2025-01-03 15:33:41 +00:00
fe47746c1f update add user with profile image upload and first draft of profile updating 2025-01-03 15:32:59 +00:00
edfe6936f5 add different color pinpoint icons 2025-01-03 15:32:06 +00:00
ea322dc2ac Complete profile image, password update functionality 2025-01-03 15:31:07 +00:00
8d97ab0345 update map variables to use env variables, fix link for itinerary report and add active link for case_itinerary 2025-01-03 15:24:17 +00:00
133d99d297 start work on dashboard and complete first draft of profile 2025-01-03 15:22:45 +00:00
96abea4198 convert map parameters to env variables, add corrected breadcrumb 2025-01-03 14:04:02 +00:00
368b4fbcd3 allow uploading profile image 2025-01-03 14:01:54 +00:00
577dee227d format 2025-01-01 06:05:07 +00:00
79bb26e9f3 format 2025-01-01 06:04:24 +00:00
109384ec99 add report page and move map button to it 2025-01-01 06:03:17 +00:00
781935821b add getRecentTravel method 2025-01-01 06:01:18 +00:00
81ba235b08 add message link to staff note signature notifications 2025-01-01 06:00:46 +00:00
c3bc40561b update notification reader 2025-01-01 05:59:21 +00:00
af41590fd3 add itinerary report page, update map page, add markers for origin and destination, add filter-itinerary-by-case method 2025-01-01 05:57:42 +00:00
03c7153565 update openMap method for itinerary report 2025-01-01 05:55:09 +00:00
b42b1ea410 fix fetch link, add filterItineraryByCase method 2025-01-01 05:52:35 +00:00
2e163d526c add location form 2024-12-31 23:08:22 +00:00
d99ef31fef update libraries 2024-12-31 23:07:58 +00:00
e5bd7c4003 add page_js to be able to add javascript specific to a page 2024-12-31 23:07:18 +00:00
67c341c390 add id for flash messages 2024-12-31 23:05:11 +00:00
ef45c6cd28 add csrf protection 2024-12-31 23:04:37 +00:00
642492411e rename caseId to memberCase 2024-12-31 23:03:45 +00:00
1d16cadc7b fix close calculations 2024-12-31 23:03:19 +00:00
e44b346788 readd stimulus library and controller 2024-12-31 23:02:32 +00:00
6a5a5c2282 add leaflet controller 2024-12-31 23:02:06 +00:00
6c340b4229 first draft of case addresses and itineraries 2024-12-31 23:01:37 +00:00
1b5ca4bd34 remove functions to place in other js files 2024-12-31 23:00:17 +00:00
7f2f6aa749 add js libraries 2024-12-31 22:59:55 +00:00
d0e48b4142 remove bootstrap for importmap library 2024-12-31 22:59:14 +00:00
66100f0eaf make bg-gradient-dark background-image important to override bootstrap 2024-12-31 22:58:43 +00:00
e207668205 remove empty map 2024-12-31 22:57:49 +00:00
5b0ededa27 remove bootstrap, popper, perfect-scrollbar, and smooth-scrollbar from javascript block and added to importmap 2024-12-25 17:19:52 +00:00
ff50c96b74 formatting. 2024-12-25 17:18:45 +00:00
52a39792e0 formatting 2024-12-25 17:18:30 +00:00
f76ca5c3cc fix typo and added case_itinerary 2024-12-25 17:17:50 +00:00
d67db33ed0 add getRoute method and format numbers returned 2024-12-25 17:17:23 +00:00
1e3a6dd612 fix getting correct breadcrumb link and highling correct nav link 2024-12-25 17:16:04 +00:00
6a9c35842f formatting 2024-12-25 17:15:12 +00:00
2206fe33c9 add case addresses link 2024-12-25 03:07:29 +00:00
fc2218ee23 add lat/lon 2024-12-25 03:01:03 +00:00
b9d165928a add vicVichy/uploader-bundle 2024-12-25 02:54:45 +00:00
f877e3f4df fix 2024-12-25 02:51:04 +00:00
2655848d96 Add environment variables for data creation for testing 2024-12-25 02:48:32 +00:00
12199b6152 add staffnote fixture 2024-12-23 03:06:40 +00:00
b87e970164 add case viewer for case workers 2024-12-23 03:06:10 +00:00
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
9decc18f42 remove background color 2024-12-22 01:19:47 +00:00
cc64846171 add notification badge with count 2024-12-22 01:19:16 +00:00
af2dd60022 add fixtures bundle for test data 2024-12-22 01:18:53 +00:00
0c902b93c4 not sure what I did here 2024-12-22 01:18:32 +00:00
ba28fcca08 add staff_notes 2024-12-22 01:17:37 +00:00
b4481eef9a remove extra tag 2024-12-22 01:17:11 +00:00
c5acb7a0f4 Fix link 2024-12-22 01:16:53 +00:00
1118fdfb45 Add resource type 2024-12-22 01:16:15 +00:00
5271f5263f Add staff pages section 2024-12-22 01:15:39 +00:00
5a531ae171 Add staff notes functionality 2024-12-22 01:15:15 +00:00
6b61d1a182 Added messages, notifications, count, and supporting elements 2024-12-22 01:13:28 +00:00
2b8682bcbb Add my_cases nav link option 2024-12-19 02:42:54 +00:00
6410005a22 move Case List and add My Cases to nav 2024-12-19 02:42:20 +00:00
71e3304154 add my-cases.html.twig template for user use 2024-12-19 02:41:38 +00:00
e6b3850b45 move list-cases twig template to admin portion 2024-12-19 02:40:59 +00:00
d193e9ba79 add ResourceType for filtering later 2024-12-19 02:40:25 +00:00
d7bddc0328 increase email string length to 64 2024-12-19 02:39:35 +00:00
a53a5d6b52 fix bug for undefined hoursUsed variable 2024-12-19 02:39:12 +00:00
3391737c45 Add fixtures to generate randomized data 2024-12-19 02:37:38 +00:00
fe44642fee Add community resource content and associated pages, links, forms, etc 2024-12-18 05:24:20 +00:00
78d149c348 Make case list available to users
Add case notes link
Move user list into admin section
2024-12-17 12:11:32 -05:00
de81c2ffb1 Hide Add Case button if not admin or case manager
Hide case filter if user not admin or case manager
Hide case edit button and case assign button if not admin or case manager
2024-12-17 12:09:00 -05:00
c76783b79f Don't display add button if not a case manager or admin
Display highlighting for referrals close to expiration
Highlight hours if < 40
2024-12-17 12:07:13 -05:00
6287ec6e2f Formatting 2024-12-17 12:05:36 -05:00
b2e90908cd Formatting 2024-12-17 12:05:16 -05:00
c7c14b5726 Formatting 2024-12-17 12:04:48 -05:00
f6addcc199 Add populateNotes method to populate the appropriate notes within a referral 2024-12-17 12:03:25 -05:00
de08885e0b Add notes and present members collections
Add time calculation and getHoursRemaining helper variable and method
2024-12-17 12:02:01 -05:00
365a486c84 Add getName helper method 2024-12-17 11:57:10 -05:00
c2710b7142 Add PRESENT_LINK constant 2024-12-17 11:56:38 -05:00
db756d83e4 Add NoteController and associated templates, entities, repository. 2024-12-17 11:56:14 -05:00
803ce84996 Convert to use NavList::PRESENT_LINK constant 2024-12-17 11:54:14 -05:00
ef053bae29 Convert to use NavList::PRESENT_LINK constant 2024-12-17 11:53:58 -05:00
a42ce28f14 Use Breadcrumb class
Convert to use NavList::PRESENT_LINK constant
2024-12-17 11:53:45 -05:00
f17be14174 Convert to use NavList::PRESENT_LINK constant 2024-12-17 11:53:12 -05:00
4405cb19ff Convert to use NavList::PRESENT_LINK constant 2024-12-17 11:52:48 -05:00
5975785580 Filter case list if not admin
Convert to use NavList::PRESENT_LINK constant
2024-12-17 11:52:10 -05:00
9fc84a85e9 Convert to use NavList::PRESENT_LINK constant 2024-12-17 11:50:32 -05:00
0ca406f635 Fix CSRF not showing the token 2024-12-17 11:49:22 -05:00
804652ac67 Fix asset links 2024-12-13 09:00:01 -05:00
61d8cb2e3d Add Breadcrumb class for breadcrumb links 2024-12-10 23:12:08 -05:00
ec9abbe5c0 Revise getCaseWorkers method to add therapist and possible role 2024-12-10 23:11:51 -05:00
7130cce4a2 Update symfony to v7.2 and remove stimulus-bundle and ux-turbo 2024-12-10 23:11:00 -05:00
04dfc20a28 Fix asset links 2024-12-10 23:09:56 -05:00
1489427b80 Add repeated password field 2024-12-10 23:09:16 -05:00
809490dc44 Fix asset links 2024-12-10 23:08:39 -05:00
569e03aab0 Convert to use Breadcrumb class 2024-12-10 23:08:10 -05:00
d53222bd06 Fix asset links
Add id for table body
2024-12-10 23:07:21 -05:00
dde2cb34e4 Change asset links 2024-12-10 23:04:33 -05:00
00e4e2170c Fix asset links 2024-12-10 23:04:18 -05:00
5ed230e895 Change if block for supervisor selection 2024-12-10 23:04:02 -05:00
2bbb621a56 Fix asset links 2024-12-10 23:01:39 -05:00
3b36d4ee42 Fix display of permission checkboxes 2024-12-10 23:01:24 -05:00
885cddf6b1 Fix asset links 2024-12-10 23:00:43 -05:00
a93b83e392 Fix header 2024-12-10 22:59:44 -05:00
5d14d05019 Revise if block for case level checking 2024-12-10 22:55:18 -05:00
f81e65938d Add override level checkbox and method on form submit 2024-12-10 22:54:34 -05:00
7704319bd1 Revise case levels display 2024-12-10 22:54:01 -05:00
1eac26399f Add override level checkbox 2024-12-10 22:52:31 -05:00
354d1fbde3 Add repeated password for confirmation 2024-12-10 22:51:51 -05:00
f3a32e9d94 Convert CaseLevel to use int for comparisons 2024-12-10 22:51:36 -05:00
30f9be37ec Add method to check levels 2024-12-10 22:50:20 -05:00
6454d3db47 Update CaseController add AJAX method for checking case and user levels 2024-12-10 22:49:15 -05:00
209 changed files with 30664 additions and 18892 deletions

5
.gitmessage Normal file
View File

@ -0,0 +1,5 @@
{commit-type}: {module}
{description}
### Changes
* {change1}

View File

@ -4,32 +4,7 @@
* This file will be included onto the page via the importmap() Twig function,
* which should already be in your base.html.twig.
*/
import './bootstrap.js';
import './vendor/bootstrap/bootstrap.index.js';
import './vendor/bootstrap/dist/css/bootstrap.min.css';
import './styles/app.css';
function filterCasesByUser(userId) {
fetch('/index.php/api/filter-cases-by-user', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ userId: userId })
})
.then(response => response.json())
.then(data => {
const caseList = document.getElementById('case-list');
caseList.innerHTML = '';
data.forEach(c => {
caseList.innerHTML += `
<tr>
<td>${c.clientName}</td>
<td>${c.caseNumber}</td>
<td>${c.dcsCaseId}</td>
<td>${c.referralType}/${c.referralSource.name}<br/><a href='mailto:${c.referralSource.email}'>${c.referralSource.email}</a></td>
<td>${c.county.value}</td>
<td>${c.referrals.length}</td>
<td></td>
<td></td>
</tr>`;
})
});
}

5
assets/bootstrap.js vendored Normal file
View File

@ -0,0 +1,5 @@
import { startStimulusApp } from '@symfony/stimulus-bundle';
const app = startStimulusApp();
// register any custom, 3rd party controllers here
// app.register('some_controller_name', SomeImportedController);

11
assets/controllers.json Normal file
View File

@ -0,0 +1,11 @@
{
"controllers": {
"@symfony/ux-leaflet-map": {
"map": {
"enabled": true,
"fetch": "lazy"
}
}
},
"entrypoints": []
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

97
assets/js/app/filter.js Normal file
View File

@ -0,0 +1,97 @@
export function filterAddressesByCase() {
if (!document.getElementById('case-filter').value) {
return;
}
fetch('/api/filter-address-by-case/' + document.getElementById('case-filter').value, {
method: 'POST',
header: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(result => {
const addressList = document.getElementById('addressList');
const origin = document.getElementById('origin');
const destination = document.getElementById('destination');
origin.innerHTML = '';
destination.innerHTML = '';
addressList.innerHTML = '';
origin.innerHTML += '<option value="">-- Origin --</option>';
destination.innerHTML += '<option value="">-- Destination --</option>';
result.forEach(a => {
origin.innerHTML += `<option value='${a.id}'>${a.name}</option>`;
destination.innerHTML += `<option value='${a.id}'>${a.name}</option>`;
addressList.innerHTML += `
<tr>
<td>
<div class='d-flex px-2 py-1'>
<div class='d-flex flex-column justify-content-center'>
<h6 class='mb-0 text-small'>
${a.name}
</h6>
</div>
</div>
</td>
<td>${a.formattedAddress}</td>
<td class='align-middle text-center text-xs'>${a.lat}/${a.lon}</td>
<td class='align-middle'>
<a href='/addresses/edit/${a.id}' class='text-secondary' title='Edit Address'>
<i class='material-symbols-rounded opacity-5'>edit</i>
</a>
</td>
</tr>`;
})
});
}
export function filterItineraryByCase() {
let caseId = null;
let startDate = null;
let endDate = null;
if (document.getElementById('case-filter').value) {
caseId = document.getElementById('case-filter').value;
}
if (document.getElementById('start-date-filter').value) {
startDate = document.getElementById('start-date-filter').value;
}
if (document.getElementById('end-date-filter').value) {
endDate = document.getElementById('end-date-filter').value;
}
fetch('/api/filter-itinerary-by-case', {
method: 'POST',
header: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
caseId: caseId,
startDate: startDate,
endDate: endDate,
})
})
.then(response => response.json())
.then(result => {
const itineraryList = document.getElementById('itineraryList');
itineraryList.innerHTML = '';
result.forEach(i => {
itineraryList.innerHTML += `
<tr>
<td>${i.date}</td>
<td>${i.case}</td>
<td>${i.origin.name}</td>
<td>${i.destination.name}</td>
<td>${i.duration}</td>
<td>${i.distance}</td>
<td></td>
</tr>`;
})
});
}

View File

@ -0,0 +1,51 @@
export function createItinerary() {
if (!document.getElementById('case-filter').value) {
return;
}
let date = document.getElementById('date');
date.value = new Date().toLocaleDateString();
let btn = document.getElementById('create-itinerary');
btn.setAttribute('data-bs-toggle', 'modal');
btn.setAttribute('data-bs-target', '#exampleModalMessage');
btn.click();
}
export function addLocationToItinerary() {
let date = document.getElementById('date').value;
let origin = document.getElementById('origin').value;
let destination = document.getElementById('destination').value;
let departure = document.getElementById('departure').value;
let caseMileage = document.getElementById('case-mileage').checked;
let caseId = document.getElementById('case-filter').value;
fetch('/api/add-location-to-itinerary', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
caseId: caseId,
date: date,
origin: origin,
destination: destination,
departure: departure,
caseMileage: caseMileage
})
})
.then(response => response.json())
.then(data => {
if (data.success === true) {
$('#close-modal').click();
}
});
}
export function openMap() {
document.getElementById('caseId').value = document.getElementById('case-filter').value;
document.getElementById('startDate').value = document.getElementById('start-date-filter').value;
document.getElementById('endDate').value = document.getElementById('end-date-filter').value;
document.getElementById('map-form').submit();
}

32
assets/js/app/message.js Normal file
View File

@ -0,0 +1,32 @@
export function messageSupervisor() {
let btn = document.getElementById('message-supervisor');
btn.setAttribute('data-bs-toggle', 'modal');
btn.setAttribute('data-bs-target', '#message-modal');
btn.click();
}
export function openMessage() {
let btn = document.getElementById('open-message');
btn.setAttribute('data-bs-toggle', 'modal');
btn.setAttribute('data-bs-target', '#message-modal');
btn.click();
}
export function sendMessage() {
fetch('/api/send-message', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
case: document.getElementById('my-cases').value,
message: document.getElementById('message').value
})
})
.then(response => response.json())
.then(data => {
if (data.success === true) {
$('#close-modal').click();
}
});
}

91
assets/js/app/notes.js Normal file
View File

@ -0,0 +1,91 @@
export function filterNotes()
{
let referralId = document.getElementById('referralList').value;
let startDate = document.getElementById('startDate').value;
let endDate = document.getElementById('endDate').value;
let caseId = null;
if (referralId.substr(0, 5) == 'case-') {
caseId = referralId.substr(5);
referralId = null;
}
fetch('/api/filter-notes', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
'referral': referralId,
'startDate': startDate,
'endDate': endDate,
'case': caseId
})
})
.then(response => response.json())
.then(data => {
const noteList = document.getElementById('note-list');
noteList.innerHTML = '';
data.forEach(i => {
let duration = (parseInt(i.duration) / 60).toFixed(2);
noteList.innerHTML += `
<tr>
<td>${i.date}<br/>
${i.startTime}-${i.endTime} (${duration})</td>
<td class='text-center'>${i.location}</td>
<td class='text-center'>${i.method}</td>
<td'>${i.members}</td>
<td style='text-align: right;'>
<a href='/edit-note/${i.noteType}/${i.id}' class='text-secondary' title='Edit Note'>
<i class="material-symbols-rounded opacity-5">edit</i>
</a>
</td>
</tr>`;
})
});
}
export function calcTime(precision = 15) {
if (!document.getElementById('note_form_startTime').value || !document.getElementById('note_form_endTime').value) {
console.log('ending');
return;
}
let st = document.getElementById('note_form_startTime').value.split(':');
let et = document.getElementById('note_form_endTime').value.split(':');
let sd = new Date();
let ed = new Date();
sd.setHours(st[0]);
sd.setMinutes(st[1]);
sd.setSeconds(0);
ed.setHours(et[0]);
ed.setMinutes(et[1]);
ed.setSeconds(0);
let timediff = (ed.getTime() - sd.getTime()) / 1000;
let increments = (timediff / 60) / precision;
if (isFloat(increments)) {
let mod = (timediff / 60) % precision;
if (mod >= (precision / 2)) {
increments++;
}
increments = parseInt(increments);
}
document.getElementById('case-mins').value = (increments * precision)+' minutes';
document.getElementById('case-hours').value = ((increments * precision) / 60)+' hours';
}
export function autosaveNote()
{
}
export function checkNotes() {
}

21
assets/js/app/user.js Normal file
View File

@ -0,0 +1,21 @@
export function createSignatureBlock() {
pad = new SignaturePad(document.getElementById('signature_pad'));
const ratio = Math.max(window.devicePixelRatio || 1, 1);
canvas.width = canvas.offsetWidth * ratio;
canvas.height = canvas.offsetHeight * ratio;
canvas.getContext("2d").scale(ratio, ratio);
//pad.clear(); // otherwise isEmpty() might return incorrect value
}
export function clearSignatureBlock() {
//const pad = new SignaturePad(document.getElementById('signature_pad'));
pad.clear();
}
export function saveSignatureBlock() {
//const pad = new SignaturePad(document.getElementById('signature_pad'));
const data = pad.toData();
document.getElementById('signature').value = data;
return true;
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,14 @@
.notification .badge {
position: absolute;
top: -8px;
right: 5px;
padding: 5px 9px;
border-radius: 50%;
background-color: red;
color: white;
font-size: 6pt;
}
a {
text-decoration: none !important;
}

View File

@ -14,39 +14,42 @@
"doctrine/orm": "^3.3",
"phpdocumentor/reflection-docblock": "^5.4",
"phpstan/phpdoc-parser": "^1.33",
"symfony/asset": "7.1.*",
"symfony/asset-mapper": "7.1.*",
"symfony/console": "7.1.*",
"symfony/doctrine-messenger": "7.1.*",
"symfony/dotenv": "7.1.*",
"symfony/expression-language": "7.1.*",
"symfony-cmf/slugifier-api": "^2.1",
"symfony/asset": "7.2.*",
"symfony/asset-mapper": "7.2.*",
"symfony/console": "7.2.*",
"symfony/doctrine-messenger": "7.2.*",
"symfony/dotenv": "7.2.*",
"symfony/expression-language": "7.2.*",
"symfony/flex": "^2",
"symfony/form": "7.1.*",
"symfony/framework-bundle": "7.1.*",
"symfony/http-client": "7.1.*",
"symfony/intl": "7.1.*",
"symfony/mailer": "7.1.*",
"symfony/mime": "7.1.*",
"symfony/form": "7.2.*",
"symfony/framework-bundle": "7.2.*",
"symfony/http-client": "7.2.*",
"symfony/intl": "7.2.*",
"symfony/mailer": "7.2.*",
"symfony/mime": "7.2.*",
"symfony/monolog-bundle": "^3.0",
"symfony/notifier": "7.1.*",
"symfony/process": "7.1.*",
"symfony/property-access": "7.1.*",
"symfony/property-info": "7.1.*",
"symfony/runtime": "7.1.*",
"symfony/security-bundle": "7.1.*",
"symfony/serializer": "7.1.*",
"symfony/stimulus-bundle": "^2.21",
"symfony/string": "7.1.*",
"symfony/translation": "7.1.*",
"symfony/twig-bundle": "7.1.*",
"symfony/uid": "7.1.*",
"symfony/ux-turbo": "^2.21",
"symfony/validator": "7.1.*",
"symfony/web-link": "7.1.*",
"symfony/yaml": "7.1.*",
"symfony/notifier": "7.2.*",
"symfony/process": "7.2.*",
"symfony/property-access": "7.2.*",
"symfony/property-info": "7.2.*",
"symfony/runtime": "7.2.*",
"symfony/security-bundle": "7.2.*",
"symfony/serializer": "7.2.*",
"symfony/stimulus-bundle": "^2.22",
"symfony/string": "7.2.*",
"symfony/translation": "7.2.*",
"symfony/twig-bundle": "7.2.*",
"symfony/uid": "7.2.*",
"symfony/ux-leaflet-map": "^2.22",
"symfony/ux-map": "^2.22",
"symfony/validator": "7.2.*",
"symfony/web-link": "7.2.*",
"symfony/yaml": "7.2.*",
"twig/extra-bundle": "^2.12|^3.0",
"twig/intl-extra": "^3.15",
"twig/twig": "^2.12|^3.0"
"twig/twig": "^2.12|^3.0",
"vich/uploader-bundle": "^2.5"
},
"config": {
"allow-plugins": {
@ -95,17 +98,23 @@
"extra": {
"symfony": {
"allow-contrib": false,
"require": "7.1.*"
"require": "7.2.*"
}
},
"require-dev": {
"ext-dom": "*",
"ext-simplexml": "*",
"ext-xml": "*",
"doctrine/doctrine-fixtures-bundle": "^4.0",
"fakerphp/faker": "^1.24",
"phpstan/phpstan": "^2.1",
"phpunit/phpunit": "^9.5",
"symfony/browser-kit": "7.1.*",
"symfony/css-selector": "7.1.*",
"symfony/debug-bundle": "7.1.*",
"symfony/browser-kit": "7.2.*",
"symfony/css-selector": "7.2.*",
"symfony/debug-bundle": "7.2.*",
"symfony/maker-bundle": "^1.0",
"symfony/phpunit-bridge": "^7.1",
"symfony/stopwatch": "7.1.*",
"symfony/web-profiler-bundle": "7.1.*"
"symfony/phpunit-bridge": "^7.2",
"symfony/stopwatch": "7.2.*",
"symfony/web-profiler-bundle": "7.2.*"
}
}

View File

@ -11,4 +11,8 @@ return [
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true],
Symfony\UX\Map\UXMapBundle::class => ['all' => true],
Vich\UploaderBundle\VichUploaderBundle::class => ['all' => true],
];

11
config/packages/csrf.yaml Normal file
View File

@ -0,0 +1,11 @@
# Enable stateless CSRF protection for forms and logins/logouts
framework:
form:
csrf_protection:
token_id: submit
csrf_protection:
stateless_token_ids:
- submit
- authenticate
- logout

View File

@ -1,16 +1,16 @@
# see https://symfony.com/doc/current/reference/configuration/framework.html
framework:
secret: '%env(APP_SECRET)%'
#csrf_protection: true
secret: "%env(APP_SECRET)%"
csrf_protection: true
# Note that the session will be started ONLY if you read or write from it.
session: true
# Note that the session will be started ONLY if you read or write from it.
session: true
#esi: true
#fragments: true
#esi: true
#fragments: true
when@test:
framework:
test: true
session:
storage_factory_id: session.storage.factory.mock_file
framework:
test: true
session:
storage_factory_id: session.storage.factory.mock_file

View File

@ -7,21 +7,32 @@ security:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
entity:
class: App\Entity\User
class: App\Entity\System\User
property: username
# used to reload user from session & other features (e.g. switch_user)
firewalls:
profile_images:
pattern: ^/uploads/user_images/
security: false
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
pattern:
- ^/_profiler
- ^/_wdt
- ^/css
- ^/images
- ^/js
- ^/uploads
- ^/favicon.ico
security: false
main:
lazy: true
provider: app_user_provider
user_checker: App\Security\UserChecker
form_login:
login_path: app_login
check_path: app_login
enable_csrf: false
default_target_path: /dashboard
default_target_path: app_dashboard
logout:
path: app_logout
# where to redirect after logout

View File

@ -1,5 +1,10 @@
twig:
file_name_pattern: '*.twig'
globals:
mileage_rate: '%env(MILEAGE_RATE)%'
company_timezone: '%env(COMPANY_TIMEZONE)%'
company_image_path: '%env(COMPANY_IMAGE_PATH)%'
user_image_path: '%env(USER_IMAGE_PATH)%'
when@test:
twig:

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

@ -0,0 +1,20 @@
vich_uploader:
db_driver: orm
metadata:
auto_detection: true
cache: file
type: attribute
mappings:
imageName:
uri_prefix: "%app.path.imageName%"
upload_destination: "%kernel.project_dir%/public/upload/user/profiles"
namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
inject_on_load: false
delete_on_update: true
delete_on_remove: true
#mappings:
# products:
# uri_prefix: /images/products
# upload_destination: '%kernel.project_dir%/public/images/products'
# namer: Vich\UploaderBundle\Naming\SmartUniqueNamer

View File

@ -4,6 +4,7 @@
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters:
app.path.imageName: /upload/user/profiles
services:
# default configuration for services in *this* file

View File

@ -16,13 +16,79 @@ return [
'path' => './assets/app.js',
'entrypoint' => true,
],
'@hotwired/stimulus' => [
'version' => '3.2.2',
],
'@symfony/stimulus-bundle' => [
'path' => './vendor/symfony/stimulus-bundle/assets/dist/loader.js',
],
'@hotwired/turbo' => [
'version' => '7.3.0',
'@symfony/ux-leaflet-map' => [
'path' => './vendor/symfony/ux-leaflet-map/assets/dist/map_controller.js',
],
'jquery' => [
'version' => '3.7.1',
],
'@hotwired/stimulus' => [
'version' => '3.2.2',
],
'leaflet' => [
'version' => '1.9.4',
],
'leaflet/dist/leaflet.min.css' => [
'version' => '1.9.4',
'type' => 'css',
],
'bootstrap' => [
'version' => '5.3.3',
],
'@popperjs/core' => [
'version' => '2.11.8',
],
'bootstrap/dist/css/bootstrap.min.css' => [
'version' => '5.3.3',
'type' => 'css',
],
'perfect-scrollbar' => [
'version' => '1.5.6',
],
'perfect-scrollbar/css/perfect-scrollbar.min.css' => [
'version' => '1.5.6',
'type' => 'css',
],
'smooth-scrollbar' => [
'version' => '8.8.4',
],
'tslib' => [
'version' => '2.8.1',
],
'core-js/es/map' => [
'version' => '3.39.0',
],
'core-js/es/set' => [
'version' => '3.39.0',
],
'core-js/es/weak-map' => [
'version' => '3.39.0',
],
'core-js/es/array/from' => [
'version' => '3.39.0',
],
'core-js/es/object/assign' => [
'version' => '3.39.0',
],
'notify.js' => [
'version' => '0.0.3',
],
'underscore' => [
'version' => '1.5.2',
],
'chartjs' => [
'version' => '0.3.24',
],
'signature_pad' => [
'version' => '5.0.4',
],
'tinymce' => [
'version' => '7.6.0',
],
'moment' => [
'version' => '2.30.1',
],
];

1
public/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
uploads

View File

@ -2,6 +2,16 @@
use App\Kernel;
if (preg_match("/theme\//", $_SERVER['REQUEST_URI'])) {
print file_get_contents(dirname(__FILE__).$_SERVER['REQUEST_URI']);
exit;
}
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
$_SERVER['HTTPS'] = 'on';
$_SERVER['SERVER_PORT'] = 443;
}
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {

View File

@ -1,15 +1,19 @@
<?php
namespace App\Controller;
namespace App\Controller\Admin;
use App\Entity\Supervision;
use App\Entity\User;
use App\Entity\Staff\Supervision;
use App\Entity\System\User;
use App\Factory\MessageFactory;
use App\Form\EditUserFormType;
use App\Form\SupervisorFormType;
use App\Form\UserFormType;
use App\Libs\Breadcrumb;
use App\Libs\NavList;
use App\Libs\Libs;
use App\Repository\UserRepository;
use DateTime;
use DateTimeZone;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
@ -18,6 +22,7 @@ use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\String\Slugger\SluggerInterface;
#[IsGranted('ROLE_ADMIN')]
class AdminController extends AbstractController
@ -25,7 +30,7 @@ class AdminController extends AbstractController
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly UserPasswordHasherInterface $userPasswordHasher,
private array $navLinks = []
private array $navLinks = [],
) {
$this->navLinks = NavList::LIST;
}
@ -34,7 +39,7 @@ class AdminController extends AbstractController
public function adminDashboard(#[CurrentUser()] User $user): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$this->navLinks['admin_dashboard'] = 'nav-link text-white active bg-gradient-dark';
$this->navLinks['admin_dashboard'] = NavList::PRESENT_LINK;
return $this->render(
'internal/admin/admin-dashboard.html.twig',
@ -44,7 +49,7 @@ class AdminController extends AbstractController
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_admin_dashboard'), 'Admin Dashboard')
],
'notifications' => $user->retrieveUnreadNotifications(),
'notifications' => Libs::getMessages($user, $this->entityManager),
]
)
);
@ -66,7 +71,7 @@ class AdminController extends AbstractController
$users[$idx]->setSupervisor($supervisor);
}
$this->navLinks['user_list'] = 'nav-link text-white active bg-gradient-dark';
$this->navLinks['user_list'] = NavList::PRESENT_LINK;
return $this->render(
'internal/admin/users/list-users.html.twig',
@ -77,15 +82,18 @@ class AdminController extends AbstractController
new Breadcrumb($this->generateUrl('app_list_users'), 'List Users')
],
'users' => $users,
'notifications' => $user->retrieveUnreadNotifications(),
'notifications' => Libs::getMessages($user, $this->entityManager),
]
)
);
}
#[Route('/add-user', name: 'app_add_user')]
public function addUser(Request $request, #[CurrentUser()] User $admin): Response
{
public function addUser(
Request $request,
#[CurrentUser()] User $admin,
SluggerInterface $slugger
): Response {
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$user = new User();
@ -126,8 +134,28 @@ class AdminController extends AbstractController
->setRateType($form->get('rateType')->getData())
->setRate($form->get('rate')->getData())
->setLevel($form->get('level')->getData())
->setCompany($admin->getCompany());
->setCompany($admin->getCompany())
->setActive(true)
->setPasswordChanged(new DateTime('1970-01-01 00:00:00', new DateTimeZone($_ENV['COMPANY_TIMEZONE'])))
;
if ($form->get('imageName')->getData()) {
/** @var \Symfony\Component\HttpFoundation\File\UploadedFile $file */
$file = $form['imageName']->getData();
$destination = $this->getParameter('kernel.project_dir').'/public/uploads/user_images/';
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
$newFilename = $slugger->slug($originalFilename).'-'.uniqid().'.'.$file->guessExtension();
$file->move(
$destination,
$newFilename
);
$user->setImageName($newFilename);
}
$msg = MessageFactory::createUser($admin, $user, 'Welcome', "Welcome to CM Tracker");
$this->entityManager->persist($msg);
$this->entityManager->persist($user);
$this->entityManager->flush();
@ -136,7 +164,7 @@ class AdminController extends AbstractController
return $this->redirectToRoute('app_list_users');
}
$this->navLinks['user_list'] = 'nav-link text-white active bg-gradient-dark';
$this->navLinks['user_list'] = NavList::PRESENT_LINK;
return $this->render(
'internal/admin/users/add-user.html.twig',
@ -148,7 +176,7 @@ class AdminController extends AbstractController
new Breadcrumb($this->generateUrl('app_add_user'), 'Add User')
],
'form' => $form,
'notifications' => $admin->retrieveUnreadNotifications(),
'notifications' => Libs::getMessages($admin, $this->entityManager),
]
)
);
@ -166,18 +194,34 @@ class AdminController extends AbstractController
$form = $this->createForm(EditUserFormType::class, $user);
$form->handleRequest($request);
$this->navLinks['user_list'] = 'nav-link text-white active bg-gradient-dark';
$this->navLinks['user_list'] = NavList::PRESENT_LINK;
if ($form->isSubmitted() && $form->isValid()) {
$roles = ['ROLE_USER'];
if ($form->get('caseWorker')->getData()) {
$roles[] = 'ROLE_CASE_WORKER';
}
if ($form->get('caseManager')->getData()) {
$roles[] = 'ROLE_CASE_MANAGER';
}
if ($form->get('therapist')->getData()) {
$roles[] = 'ROLE_THERAPIST';
}
if ($form->get('su')->getData()) {
$roles[] = 'ROLE_ADMIN';
}
$user->setName($form->get('name')->getData())
->setEmail($form->get('email')->getData())
->setCaseWorker($form->get('caseWorker')->getData())
->setCaseManager($form->get('caseManager')->getData())
->setTherapist($form->get('therapist')->getData())
->setSu($form->get('su')->getData())
->setRoles($roles)
->setActive((bool) $form->get('active')->getData())
->setRateType($form->get('rateType')->getData())
->setRate($form->get('rate')->getData())
->setLevel($form->get('level')->getData());
->setLevel($form->get('level')->getData())
;
$this->entityManager->flush();
@ -195,7 +239,7 @@ class AdminController extends AbstractController
],
'data' => $user,
'form' => $form,
'notifications' => $admin->retrieveUnreadNotifications(),
'notifications' => Libs::getMessages($admin, $this->entityManager),
]
)
);
@ -209,24 +253,34 @@ class AdminController extends AbstractController
/** @var User $user */
$user = $userRepo->find($id);
$prevSup = $this->entityManager->getRepository(Supervision::class)->findBy(['worker' => $user]);
$prevSup = $this->entityManager->getRepository(Supervision::class)->findOneBy(['worker' => $user]);
$form = $this->createForm(SupervisorFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var User $supervisor */
$supervisor = $form->get('supervisor')->getData();
if (count($prevSup) > 0) {
$this->entityManager->remove($prevSup[0]);
if ($prevSup) {
$prevSup->setSupervisor($supervisor);
$this->entityManager->persist($prevSup);
$this->entityManager->flush();
$this->addFlash('success', "Supervisor updated for {$user->getName()}");
} else {
$sup = new Supervision();
$sup->setWorker($user);
$sup->setSupervisor($supervisor);
$this->entityManager->persist($sup);
$this->entityManager->flush();
$this->addFlash('success', "Supervisor assigned to {$user->getName()}");
}
$sup = new Supervision();
$sup->setSupervisor($supervisor);
$sup->setWorker($user);
$supMsg = MessageFactory::createUser($admin, $supervisor, 'New Case Worker', "You've been assigned a new case worker, {$user->getName()}");
$userMsg = MessageFactory::createUser($admin, $user, 'New Staff Supervisor', "You've been assigned a new staff supervisor {$supervisor->getName()}");
$this->entityManager->persist($sup);
$this->entityManager->persist($userMsg);
$this->entityManager->persist($supMsg);
$this->entityManager->flush();
return $this->redirectToRoute('app_list_users');
@ -244,7 +298,7 @@ class AdminController extends AbstractController
'user' => $user,
'form' => $form,
'supervisors' => $userRepo->getCaseManagers($admin->getCompany()),
'notifications' => $admin->retrieveUnreadNotifications(),
'notifications' => Libs::getMessages($admin, $this->entityManager),
]
)
);

View File

@ -0,0 +1,420 @@
<?php
namespace App\Controller\Case;
use App\Entity\Case\CaseLocation;
use App\Entity\Company\CompanyDocument;
use App\Entity\Case\Member;
use App\Entity\Case\MemberCase;
use App\Entity\System\Location;
use App\Entity\System\ReferralSource;
use App\Entity\System\User;
use App\Entity\System\UserCase;
use App\Factory\MessageFactory;
use App\Form\CaseDocumentFormType;
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;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
class CaseController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager,
private array $navLinks = []
) {
$this->navLinks = NavList::LIST;
$this->navLinks['case_list'] = NavList::PRESENT_LINK;
}
#[Route('/my-cases', name: 'app_my_cases')]
public function myCases(#[CurrentUser()] User $user, Request $request): Response
{
if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$this->navLinks['my_cases'] = NavList::PRESENT_LINK;
$this->navLinks['case_list'] = NavList::DEFAULT;
$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/my-cases.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
(
strpos($request->server->get('HTTP_REFERER'), 'list-cases') !== false
? new Breadcrumb($this->generateUrl('app_list_cases'), 'Cases')
: new Breadcrumb($this->generateUrl('app_my_cases'), 'My Cases')
),
],
'notifications' => Libs::getMessages($user, $this->entityManager),
'cases' => $cases,
]
)
);
}
#[Route('/list-cases', name: 'app_list_cases')]
public function listCases(#[CurrentUser()] User $user): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$cases = $this->entityManager->getRepository(MemberCase::class)->findAll();
$workers = $this->entityManager->getRepository(User::class)->getCaseWorkers();
return $this->render(
'internal/admin/cases/list-cases.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_cases'), 'List Cases')
],
'notifications' => Libs::getMessages($user, $this->entityManager),
'cases' => $cases,
'workers' => $workers,
]
)
);
}
#[Route('/case/{caseId}', name: 'app_view_case')]
public function showCase(Request $request, #[CurrentUser()] User $user, string $caseId): Response
{
if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$case = $this->entityManager->getRepository(MemberCase::class)->find($caseId);
/** @todo validate user has access to case, check for admin, case manager of case worker */
if (!Libs::checkPermissions($user, $case, $this->entityManager)) {
throw new AccessDeniedException();
}
$sources = $this->entityManager->getRepository(ReferralSource::class)->findAll();
return $this->render(
'internal/cases/view-case.html.twig',
array_merge(
$this->navLinks,
[
'case' => $case,
'sources' => $sources,
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_cases'), 'Cases'),
new Breadcrumb($this->generateUrl('app_view_case', ['caseId' => $case->getId()]), 'View Case')
],
'notifications' => Libs::getMessages($user, $this->entityManager),
]
)
);
}
#[Route('/add-case', name: 'app_add_case')]
public function addCase(Request $request, #[CurrentUser()] User $admin): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$case = new MemberCase();
$form = $this->createForm(MemberCaseFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$case = $form->getData();
$this->entityManager->persist($case);
$this->entityManager->flush();
$this->addFlash('success', 'Case added successfully');
return $this->redirectToRoute('app_list_cases');
}
return $this->render(
'internal/admin/cases/add-case.html.twig',
array_merge(
$this->navLinks,
[
'title' => 'Add Case',
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_cases'), 'List Cases'),
new Breadcrumb($this->generateUrl('app_add_case'), 'Add Case')
],
'notifications' => Libs::getMessages($admin, $this->entityManager),
'form' => $form,
'sources' => $this->entityManager->getRepository(ReferralSource::class)->retrieveOrderedList(),
]
)
);
}
#[Route('/edit-case/{id}', name: 'app_edit_case')]
public function editCase(Request $request, #[CurrentUser()] User $admin, string $id): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$case = $this->entityManager->getRepository(MemberCase::class)->find($id);
$form = $this->createForm(MemberCaseFormType::class, $case);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$case = $form->getData();
$this->entityManager->flush();
$this->addFlash('success', 'Case updated successfully');
return $this->redirectToRoute('app_list_cases');
}
return $this->render(
'internal/admin/cases/edit-case.html.twig',
array_merge(
$this->navLinks,
[
'title' => 'Edit Case',
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_cases'), 'List Cases'),
new Breadcrumb($this->generateUrl('app_edit_case', ['id' => $id]), 'Edit Case')
],
'notifications' => Libs::getMessages($admin, $this->entityManager),
'form' => $form,
'case' => $case,
'sources' => $this->entityManager->getRepository(ReferralSource::class)->retrieveOrderedList(),
]
)
);
}
#[Route('/assign-case/{id}', name: 'app_assign_case')]
public function assignCase(string $id, Request $request, #[CurrentUser()] User $admin): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$caseWorkers = $this->entityManager->getRepository(User::class)->getCaseWorkers();
$case = $this->entityManager->getRepository(MemberCase::class)->find($id);
$prevUc = $this->entityManager->getRepository(UserCase::class)->findBy(['memberCase' => $case]);
$uc = new UserCase();
$form = $this->createForm(UserCaseFormType::class, $uc);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user = $form->get('user')->getData();
$uc = $form->getData();
$uc->setMemberCase($case);
$uc->setUser($user);
if (count($prevUc) > 0) {
$this->entityManager->remove($prevUc[0]);
$this->entityManager->flush();
}
$msg = MessageFactory::createNewCase(
$admin,
$user,
$this->generateUrl('app_view_case', ['caseId' => $case->getId()->toString()])
);
$this->entityManager->persist($uc);
$this->entityManager->persist($msg);
$this->entityManager->flush();
$this->addFlash('success', 'Case assigned successfully');
return $this->redirectToRoute('app_list_cases');
}
return $this->render(
'internal/admin/cases/assign-case.html.twig',
array_merge(
$this->navLinks,
[
'title' => 'Assign Case',
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_cases'), 'List Cases'),
new Breadcrumb($this->generateUrl('app_assign_case', ['id' => $id]), 'Assign User')
],
'notifications' => Libs::getMessages($admin, $this->entityManager),
'case' => $case,
'form' => $form,
'id' => $id,
'caseWorkers' => $caseWorkers,
'assignedWorkerId' => (count($case->getUserCases()) > 0 ? $case->getUserCases()->first()->getUser()->getId() : null),
]
)
);
}
#[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);
$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' => Libs::getMessages($user, $this->entityManager),
'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';
$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' => Libs::getMessages($user, $this->entityManager),
'form' => $form,
'cases' => $cases,
]
)
);
}
#[Route('/addresses/edit/{id}', name: 'app_case_edit_address')]
public function editCaseAddress(Request $request, string $id, #[CurrentUser()] User $user): Response
{
$this->navLinks['case_itinerary'] = NavList::PRESENT_LINK;
$this->navLinks['case_list'] = 'nav-link text-dark';
$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' => Libs::getMessages($user, $this->entityManager),
]
)
);
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Controller\Case;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response;
class GeoapifyController extends AbstractController
{
#[Route('/api/autocomplete-address/{searchText}', name: 'app_api_autocomplete_address')]
public function autocompleteAddress(string $searchText): Response
{
$params = [
'text' => $searchText,
'format' => 'json',
'apiKey' => $_ENV['GEOAPIFY_API_KEY']
];
$url = "https://api.geoapify.com/v1/autocomplete?".http_build_query($params);
$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);
return $this->json($result);
}
}

View File

@ -0,0 +1,161 @@
<?php
namespace App\Controller\Case;
use App\Entity\Case\CaseItinerary;
use App\Entity\Case\MemberCase;;
use App\Entity\System\User;
use App\Entity\System\UserCase;
use App\Libs\Breadcrumb;
use App\Libs\Libs;
use App\Libs\NavList;
use DateTime;
use DateTimeZone;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
use Symfony\UX\Map\InfoWindow;
use Symfony\UX\Map\Map;
use Symfony\UX\Map\Marker;
use Symfony\UX\Map\Point;
use Symfony\UX\Map\Polyline;
class ItineraryController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager,
private array $navLinks = []
) {
$this->navLinks = NavList::LIST;
}
#[Route('/itinerary/report', name: 'app_report_itinerary')]
public function reportItinerary(Request $request, #[CurrentUser()] ?User $user): Response
{
$this->navLinks['case_itinerary'] = NavList::PRESENT_LINK;
$itineraries = $this->entityManager->getRepository(CaseItinerary::class)->getRecentTravel(
$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/itinerary/report.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_dashboard'), 'Dashboard'),
],
'notifications' => Libs::getMessages($user, $this->entityManager),
'itineraries' => $itineraries,
'cases' => $cases
]
)
);
}
#[Route('/itinerary/map', name: 'app_map_itinerary')]
public function mapItinerary(Request $request, #[CurrentUser()] ?User $user): Response
{
$this->navLinks['case_itinerary'] = NavList::PRESENT_LINK;
$case = null;
if ($request->getPayload()->get('caseId')) {
$case = $this->entityManager->getRepository(MemberCase::class)->find($request->getPayload()->get('caseId'));
}
$startDate = (
$request->getPayload()->get('startDate')
?
new DateTime($request->getPayload()->get('startDate'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']))
:
null);
$endDate = (
$request->getPayload()->get('endDate')
?
new DateTime($request->getPayload()->get('endDate'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']))
:
null);
$itineraries = $this->entityManager->getRepository(CaseItinerary::class)->getRecentTravel($user, [
'case' => $case,
'from' => $startDate,
'to' => $endDate,
]);
$map = new Map('default');
$map->center(new Point($_ENV['MAP_CENTER_LAT'], $_ENV['MAP_CENTER_LON']))
->zoom($_ENV['MAP_ZOOM_LEVEL'])
;
$total_distance = 0;
$total_duration = new DateTime('00:00:00');
foreach ($itineraries as $itinerary) {
/** @var CaseItinerary $itinerary */
$map->addMarker(new Marker(
position: new Point(
$itinerary->getOriginLocation()->getLat(),
$itinerary->getOriginLocation()->getLon()
),
title: $itinerary->getOriginLocation()->getName(),
infoWindow: new InfoWindow(
content: $itinerary->originInfoWindow(),
)
));
$map->addMarker(new Marker(
position: new Point(
$itinerary->getDestLocation()->getLat(),
$itinerary->getDestLocation()->getLon()
),
title: $itinerary->getDestLocation()->getName(),
infoWindow: new InfoWindow(
content: $itinerary->destinationInfoWindow(),
)
));
/** @var CaseItinerary $itinerary */
$map->addPolyline(new Polyline(
points: $itinerary->getGPSPolyLines(),
infoWindow: new InfoWindow(
content: $itinerary->getMemberCase()->getCaseName()
),
extra: ['color' => '#FF0000']
));
$total_distance += $itinerary->getDistance();
$total_duration->add($itinerary->getDuration());
}
$map->fitBoundsToMarkers(true);
$diff = new DateTime('00:00:00');
$di = $diff->diff($total_duration);
return $this->render(
'internal/cases/itinerary/map.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_my_cases'), 'My Cases'),
new Breadcrumb($this->generateUrl('app_report_itinerary'), 'Itinerary Report'),
],
'notifications' => Libs::getMessages($user, $this->entityManager),
'map' => $map,
'total_distance' => $total_distance,
'total_duration' => $di->format("%H:%i'%s''"),
]
)
);
}
}

View File

@ -0,0 +1,210 @@
<?php
namespace App\Controller\Case;
use App\Entity\Company\CompanyDocument;
use App\Entity\Case\Member;
use App\Entity\Case\MemberCase;;
use App\Entity\Case\MemberDocument;
use App\Entity\System\User;
use App\Entity\System\UserCase;
use App\Form\MemberFormType;
use App\Libs\Breadcrumb;
use App\Libs\Libs;
use App\Libs\NavList;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
class MemberController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager,
private array $navLinks = [],
) {
$this->navLinks = NavList::LIST;
$this->navLinks['case_list'] = NavList::PRESENT_LINK;
}
#[Route('/list-members/{id}', name: 'app_case_members')]
public function listMembers(Request $request, #[CurrentUser()] User $user, string $id): Response
{
$case = $this->entityManager->getRepository(MemberCase::class)->find($id);
$members = $this->entityManager->getRepository(Member::class)->getCaseMembersByName($case);
return $this->render(
'internal/cases/members/list-members.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_cases'), 'List Cases'),
new Breadcrumb($this->generateUrl('app_case_members', ['id' => $id]), 'List Members'),
],
'notifications' => Libs::getMessages($user, $this->entityManager),
'case' => $case,
'members' => $members,
]
)
);
}
#[Route('/add-member/{id}', name: 'app_case_add_member')]
public function addMember(Request $request, #[CurrentUser()] User $user, string $id): Response
{
/** @var MemberCase $case */
$case = $this->entityManager->getRepository(MemberCase::class)->find($id);
/** @var UserCase $userCase */
$userCase = $this->entityManager->getRepository(UserCase::class)->findOneBy(['memberCase' => $case]);
/** @var User $caseWorker */
$caseWorker = $userCase->getUser();
/** @var array $docs<int, CompanyDocuments> */
$docs = $this->entityManager->getRepository(CompanyDocument::class)->findBy(['company' => $user->getCompany()], ['title' => 'ASC']);
$member = new Member();
$form = $this->createForm(MemberFormType::class, $member, ['docs' => $docs]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$member = $form->getData();
$member->setCaseId($case)
->setChild(($form->get('isChild') ? true : false))
->setParent(($form->get('isParent') ? true : false))
->setAdultChild(($form->get('isAdultChild') ? true : false))
->setLegalGuardian(($form->get('isLegalGuardian') ? true : false))
->setParentsLiveTogether(($form->get('parentsLiveTogether') ? true : false))
->setDcsApproved(($form->get('dcsApproved') ? true : false))
;
$this->entityManager->persist($member);
$this->entityManager->flush();
$selectedDocs = $form->get('docs');
foreach ($selectedDocs->getData() as $doc) {
$dbDoc = $this->entityManager->getRepository(CompanyDocument::class)->find($doc);
if (!$dbDoc) {
continue;
}
$md = new MemberDocument();
$md->setClient($member)
->setDocument($dbDoc)
->setCaseWorker($caseWorker)
;
$this->entityManager->persist($md);
$this->entityManager->flush();
}
$this->addFlash(
'success',
'Member added successfully'
);
return $this->redirectToRoute('app_case_members', ['id' => $case->getId()]);
}
return $this->render(
'internal/cases/members/add-member.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_cases'), 'List Cases'),
new Breadcrumb($this->generateUrl('app_case_members', ['id' => $id]), 'List Members'),
new Breadcrumb($this->generateUrl('app_case_add_member', ['id' => $id]), 'Add Member'),
],
'notifications' => Libs::getMessages($user, $this->entityManager),
'case' => $case,
'form' => $form->createView(),
'docs' => $docs,
]
)
);
}
#[Route('/case/{caseId}/edit-member/{memberId}', name: 'app_case_edit_member')]
public function editMember(Request $request, #[CurrentUser()] User $user, string $caseId, string $memberId): Response
{
/** @var Member $member */
$member = $this->entityManager->getRepository(Member::class)->find($memberId);
/** @var MemberCase $case */
$case = $this->entityManager->getRepository(MemberCase::class)->find($caseId);
/** @var array<int, CompanyDocuments> $docs */
$docs = $this->entityManager->getRepository(CompanyDocument::class)->findBy(['company' => $user->getCompany()], ['title' => 'ASC']);
/** @var array<int, MemberDocument> $memberDocs */
$memberDocs = $this->entityManager->getRepository(MemberDocument::class)->findBy(['client' => $member]);
$memberDbDocs = [];
foreach($memberDocs as $md) {
$memberDbDocs[] = $md->getDocument()->getId()->toString();
}
foreach ($docs as $idx => $d) {
if (in_array($d->getId()->toString(), $memberDbDocs)) {
$docs[$idx]->setSelected();
}
}
$form = $this->createForm(MemberFormType::class, $member, ['docs' => $docs]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$member = $form->getData();
$member->setChild(($form->get('isChild') ? true : false))
->setParent(($form->get('isParent') ? true : false))
->setAdultChild(($form->get('isAdultChild') ? true : false))
->setLegalGuardian(($form->get('isLegalGuardian') ? true : false))
->setParentsLiveTogether(($form->get('parentsLiveTogether') ? true : false))
->setDcsApproved(($form->get('dcsApproved') ? true : false))
;
$this->entityManager->getRepository(MemberDocument::class)->removeUnsigned($member);
$selectedDocs = $form->get('docs')->getData();
foreach ($selectedDocs as $d) {
$md = new MemberDocument();
$md->setClient($member)
->setCaseWorker($user)
->setDocument($d)
;
$this->entityManager->persist($md);
$this->entityManager->flush();
}
$this->entityManager->flush();
$this->addFlash(
'success',
'Member updated successfully'
);
return $this->redirectToRoute('app_case_members', ['id' => $caseId]);
}
return $this->render(
'internal/cases/members/edit-member.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_cases'), 'Cases'),
new Breadcrumb($this->generateUrl('app_case_members', ['id' => $caseId]), 'Members'),
new Breadcrumb($this->generateUrl('app_case_edit_member', ['caseId' => $caseId, 'memberId' => $memberId]), 'Edit Member'),
],
'notifications' => Libs::getMessages($user, $this->entityManager),
'member' => $member,
'form' => $form->createView(),
'caseId' => $caseId,
'docs' => $docs,
'selectedDocs' => $memberDbDocs,
]
)
);
}
}

View File

@ -0,0 +1,203 @@
<?php
namespace App\Controller\Case;
use App\Entity\Case\Member;
use App\Entity\Case\MemberCase;;
use App\Entity\Case\Referral;
use App\Entity\Case\StandardNote;
use App\Entity\Case\StandardNoteMember;
use App\Entity\System\User;
use App\Entity\System\UserCase;
use App\Entity\Case\VisitNote;
use App\Entity\Case\VisitNoteMembers;
use App\Enums\Case\NoteLocation;
use App\Enums\Case\NoteMethod;
use App\Enums\Case\ReferralServiceType;
use App\Form\StandardNoteFormType;
use App\Form\VisitNoteFormType;
use App\Libs\Breadcrumb;
use App\Libs\Libs;
use App\Libs\NavList;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
class NoteController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager,
private array $navLinks = [],
) {
$this->navLinks = NavList::LIST;
$this->navLinks['case_notes'] = NavList::PRESENT_LINK;
}
#[Route('/list-notes/{caseId?null}', name: 'app_list_notes')]
public function listNotes(string $caseId = null, #[CurrentUser()] User $user, Request $request): Response
{
/** @var UserCase[] $cases */
$cases = $this->entityManager->getRepository(UserCase::class)->findBy(['user' => $user]);
$caseNotes = null;
$case = null;
if ($caseId != 'null') {
$case = $this->entityManager->getRepository(MemberCase::class)->find($caseId);
$params = [
'case' => $case,
'referral' => null,
'startDate' => null,
'endDate' => null,
];
$caseNotes = array_merge(
$this->entityManager->getRepository(VisitNote::class)->filterNotes($user, $params),
$this->entityManager->getRepository(StandardNote::class)->filterNotes($user, $params),
);
}
return $this->render(
'internal/cases/notes/list-notes.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_notes'), 'List Notes')
],
'notifications' => Libs::getMessages($user, $this->entityManager),
'cases' => $cases,
'caseNotes' => $caseNotes,
'case' => $case,
]
)
);
}
#[Route('/add-note/{referralId}', name: 'app_add_note')]
public function addNote(#[CurrentUser()] User $user, Request $request, ?string $referralId = null): Response
{
if (substr($referralId, 0, 4) == 'case') {
throw $this->createNotFoundException('Select Referral from dropdown');
}
/** @var Referral $referral */
$referral = $this->entityManager->getRepository(Referral::class)->find($referralId);
$this->entityManager->getRepository(Referral::class)->populateNotes($referral);
$members = $this->entityManager->getRepository(Member::class)->findBy(['memberCase' => $referral->getMemberCase()]);
$defaultMethod = NoteMethod::BILLABLE;
$defaultLocation = NoteLocation::COMMUNITY_OUTING;
$form = $this->createForm(StandardNoteFormType::class, null, ['members' => $members]);
$template = 'internal/cases/notes/add-standard-note.html.twig';
if ($referralId == 'null') {
$referralId = null;
}
if ($referral->getServiceCode() == ReferralServiceType::VS_THBB) {
$form = $this->createForm(VisitNoteFormType::class, null, ['members' => $members]);
$template = 'internal/cases/notes/add-visit-note.html.twig';
$defaultMethod = NoteMethod::BILLABLE_SUPERVISED_VISIT;
} elseif ($referral->getServiceCode() == ReferralServiceType::VS_THBBT) {
$defaultMethod = NoteMethod::BILLABLE;
$defaultLocation = NoteLocation::VEHICLE_TRANSPORTATION;
}
$form = $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var VisitNote|StandardNote $note */
$note = $form->getData();
$note->setReferral($referral);
$this->entityManager->persist($note);
$this->entityManager->flush();
if ($form->get('members')->getData()) {
foreach ($form->get('members')->getData() as $mem) {
if ($referral->getServiceCode() == ReferralServiceType::VS_THBB) {
$nm = new VisitNoteMembers();
$nm->setVisitNote($note)
->setPerson($mem)
;
} else {
$nm = new StandardNoteMember();
$nm->setStandardNote($note)
->setPerson($mem)
;
}
$this->entityManager->persist($nm);
$this->entityManager->flush();
}
}
$this->addFlash('success', 'Note added successfully');
return $this->redirectToRoute('app_list_notes');
}
return $this->render(
$template,
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_notes'), 'List Notes')
],
'notifications' => Libs::getMessages($user, $this->entityManager),
'referral' => $referral,
'form' => $form,
'members' => $members,
'default_method' => $defaultMethod,
'default_location' => $defaultLocation,
]
)
);
}
#[Route('/edit-note/{noteType}/{noteId}', name: 'app_edit_note')]
public function editNote(string $noteId, string $noteType, #[CurrentUser()] User $user, Request $request): Response
{
$form = null;
$members = [];
/** @var VisitNote|StandardNote $note */
if ($noteType == 'visit') {
/** @var VisitNote $note */
$note = $this->entityManager->getRepository(VisitNote::class)->find($noteId);
$members = $this->entityManager->getRepository(Member::class)->getMembersByCaseAndNote($note->getReferral()->getMemberCase(), $note);
$form = $this->createForm(VisitNoteFormType::class, $note, [
'members' => $members,
//'members' => $this->entityManager->getRepository(Member::class)->findBy(['memberCase' => $note->getReferral()->getMemberCase()])
]);
} elseif ($noteType == 'standard') {
$note = $this->entityManager->getRepository(StandardNote::class)->find($noteId);
$form = $this->createForm(StandardNoteFormType::class, $note, [
'members' => $members,
]);
}
return $this->render(
'internal/cases/notes/edit-note.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_notes'), 'List Notes')
],
'notifications' => Libs::getMessages($user, $this->entityManager),
'note' => $note,
'referral' => $note->getReferral(),
'form' => $form,
'noteType' => $noteType,
'members' => $members,
]
)
);
}
}

View File

@ -1,11 +1,15 @@
<?php
namespace App\Controller;
namespace App\Controller\Case;
use App\Entity\MemberCase;
use App\Entity\Referral;
use App\Entity\User;
use App\Entity\Case\MemberCase;;
use App\Entity\Case\Referral;
use App\Entity\System\User;
use App\Entity\System\UserCase;
use App\Factory\MessageFactory;
use App\Form\ReferralFormType;
use App\Libs\Breadcrumb;
use App\Libs\Libs;
use App\Libs\NavList;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@ -16,16 +20,30 @@ use Symfony\Component\Security\Http\Attribute\CurrentUser;
class ReferralController extends AbstractController
{
/**
* Variable to store unread notification messages
*
* @var array
*/
private array $msgs;
public function __construct(
private EntityManagerInterface $entityManager,
private array $navLinks = []
) {
$this->navLinks = NavList::LIST;
if (strpos($_SERVER['HTTP_REFERER'], 'my-cases') !== false) {
$this->navLinks['my_cases'] = NavList::PRESENT_LINK;
} else {
$this->navLinks['case_list'] = NavList::PRESENT_LINK;
}
}
#[Route('/list-referrals/{id}', name: 'app_list_referrals')]
public function listReferrals(Request $request, #[CurrentUser()] User $user, string $id): Response
public function listReferrals(#[CurrentUser()] User $user, string $id, Request $request): Response
{
$this->msgs = Libs::getMessages($user, $this->entityManager);
$case = $this->entityManager->getRepository(MemberCase::class)->find($id);
$openReferrals = $this->entityManager->getRepository(Referral::class)->getActiveReferrals($case);
$closedReferrals = $this->entityManager->getRepository(Referral::class)->getClosedReferrals($case);
@ -36,10 +54,14 @@ class ReferralController extends AbstractController
$this->navLinks,
[
'breadcrumbs' => [
'Case',
'Referrals'
(
strpos($request->server->get('HTTP_REFERER'), 'my-cases') !== false
? new Breadcrumb($this->generateUrl('app_my_cases'), 'My Cases')
: new Breadcrumb($this->generateUrl('app_list_cases'), 'List Cases')
),
new Breadcrumb($this->generateUrl('app_list_referrals', ['id' => $case->getId()]), 'Referrals'),
],
'notifications' => $user->retrieveUnreadNotifications(),
'notifications' => $this->msgs,
'case' => $case,
'openReferrals' => $openReferrals,
'closedReferrals' => $closedReferrals,
@ -51,7 +73,12 @@ class ReferralController extends AbstractController
#[Route('/add-referral/{id}', name: 'app_case_add_referral')]
public function addReferral(Request $request, #[CurrentUser()] User $user, string $id): Response
{
$this->denyAccessUnlessGranted(['ROLE_ADMIN', 'ROLE_CASE_MANAGER']);
$this->msgs = Libs::getMessages($user, $this->entityManager);
$case = $this->entityManager->getRepository(MemberCase::class)->find($id);
/** @var UserCase $uc */
$uc = $this->entityManager->getRepository(UserCase::class)->findBy(['memberCase' => $case]);
$referral = new Referral();
$form = $this->createForm(ReferralFormType::class, $referral);
@ -62,6 +89,9 @@ class ReferralController extends AbstractController
$referral = $form->getData();
$referral->setMemberCase($case);
$msg = MessageFactory::createReferral($user, $uc->getUser(), $case);
$this->entityManager->persist($msg);
$this->entityManager->persist($referral);
$this->entityManager->flush();
@ -74,10 +104,11 @@ class ReferralController extends AbstractController
$this->navLinks,
[
'breadcrumbs' => [
'Case',
'Add Referral'
new Breadcrumb($this->generateUrl('app_list_cases'), 'List Cases'),
new Breadcrumb($this->generateUrl('app_list_referrals', ['id' => $case->getId()]), 'Referrals'),
new Breadcrumb($this->generateUrl('app_case_add_referral', ['id' => $case->getId()]), 'Add Referral')
],
'notifications' => $user->retrieveUnreadNotifications(),
'notifications' => $this->msgs,
'case' => $case,
'form' => $form,
]
@ -88,8 +119,12 @@ class ReferralController extends AbstractController
#[Route('/case/{caseId}/edit-referral/{referralId}', name: 'app_case_edit_referral')]
public function editReferral(Request $request, #[CurrentUser()] User $user, string $caseId, string $referralId): Response
{
$this->denyAccessUnlessGranted(['ROLE_ADMIN', 'ROLE_CASE_MANAGER']);
$referral = $this->entityManager->getRepository(Referral::class)->find($referralId);
$case = $this->entityManager->getRepository(MemberCase::class)->find($caseId);
/** @var UserCase $uc */
$uc = $this->entityManager->getRepository(UserCase::class)->findBy(['case' => $case]);
$form = $this->createForm(ReferralFormType::class, $referral);
$form->handleRequest($request);
@ -97,6 +132,9 @@ class ReferralController extends AbstractController
if ($form->isSubmitted() && $form->isValid()) {
$referral = $form->getData();
$msg = MessageFactory::createReferral($user, $uc->getUser(), $case);
$this->entityManager->persist($msg);
$this->entityManager->flush();
return $this->redirectToRoute('app_list_referrals', ['id' => $case->getId()]);
@ -108,10 +146,11 @@ class ReferralController extends AbstractController
$this->navLinks,
[
'breadcrumbs' => [
'Case',
'Edit Referral'
new Breadcrumb($this->generateUrl('app_list_cases'), 'List Cases'),
new Breadcrumb($this->generateUrl('app_list_referrals', ['id' => $case->getId()]), 'Referrals'),
new Breadcrumb($this->generateUrl('app_case_edit_referral', ['caseId' => $case->getId(), 'referralId' => $referral->getId()]), 'Edit Referral'),
],
'notifications' => $user->retrieveUnreadNotifications(),
'notifications' => Libs::getMessages($user, $this->entityManager),
'case' => $case,
'form' => $form,
'referral' => $referral,

View File

@ -1,209 +0,0 @@
<?php
namespace App\Controller;
use App\Entity\MemberCase;
use App\Entity\ReferralSource;
use App\Entity\User;
use App\Entity\UserCase;
use App\Form\MemberCaseFormType;
use App\Form\UserCaseFormType;
use App\Libs\Breadcrumb;
use App\Libs\NavList;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
class CaseController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager,
private array $navLinks = []
) {
$this->navLinks = NavList::LIST;
}
#[Route('/list-cases', name: 'app_list_cases')]
public function listCases(#[CurrentUser()] User $user): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$this->navLinks['case_list'] = 'nav-link text-white active bg-gradient-dark';
$cases = $this->entityManager->getRepository(MemberCase::class)->findAll();
$workers = $this->entityManager->getRepository(User::class)->getCaseWorkers();
return $this->render(
'internal/cases/list-cases.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_cases'), 'List Cases')
],
'notifications' => $user->retrieveUnreadNotifications(),
'cases' => $cases,
'workers' => $workers,
]
)
);
}
#[Route('/add-case', name: 'app_add_case')]
public function addCase(Request $request, #[CurrentUser()] User $admin): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$this->navLinks['case_list'] = 'nav-link text-white active bg-gradient-dark';
$case = new MemberCase();
$form = $this->createForm(MemberCaseFormType::class, $case);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$case = $form->getData();
$this->entityManager->persist($case);
$this->entityManager->flush();
$this->addFlash('success', 'Case added successfully');
return $this->redirectToRoute('app_list_cases');
}
return $this->render(
'internal/admin/cases/add-case.html.twig',
array_merge(
$this->navLinks,
[
'title' => 'Add Case',
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_cases'), 'List Cases'),
new Breadcrumb($this->generateUrl('app_add_case'), 'Add Case')
],
'notifications' => $admin->retrieveUnreadNotifications(),
'form' => $form,
'sources' => $this->entityManager->getRepository(ReferralSource::class)->retrieveOrderedList(),
]
)
);
}
#[Route('/edit-case/{id}', name: 'app_edit_case')]
public function editCase(Request $request, #[CurrentUser()] User $admin, string $id): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$this->navLinks['case_list'] = 'nav-link text-white active bg-gradient-dark';
$case = $this->entityManager->getRepository(MemberCase::class)->find($id);
$form = $this->createForm(MemberCaseFormType::class, $case);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$case = $form->getData();
$this->entityManager->flush();
$this->addFlash('success', 'Case updated successfully');
return $this->redirectToRoute('app_list_cases');
}
return $this->render(
'internal/admin/cases/edit-case.html.twig',
array_merge(
$this->navLinks,
[
'title' => 'Edit Case',
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_cases'), 'List Cases'),
new Breadcrumb($this->generateUrl('app_edit_case', ['id' => $id]), 'Edit Case')
],
'notifications' => $admin->retrieveUnreadNotifications(),
'form' => $form,
'case' => $case,
'sources' => $this->entityManager->getRepository(ReferralSource::class)->retrieveOrderedList(),
]
)
);
}
#[Route('/assign-case/{id}', name: 'app_assign_case')]
public function assignCase(string $id, Request $request, #[CurrentUser()] User $admin): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$this->navLinks['case_list'] = 'nav-link text-white active bg-gradient-dark';
$caseWorkers = $this->entityManager->getRepository(User::class)->getCaseWorkers();
$case = $this->entityManager->getRepository(MemberCase::class)->find($id);
$prevUc = $this->entityManager->getRepository(UserCase::class)->findBy(['memberCase' => $case]);
$uc = new UserCase();
$form = $this->createForm(UserCaseFormType::class, $uc);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user = $form->get('user')->getData();
$uc = $form->getData();
$uc->setMemberCase($case);
$uc->setUser($user);
if(!$uc->checkLevel()) {
throw new Exception('');
}
if (count($prevUc) > 0) {
$this->entityManager->remove($prevUc[0]);
$this->entityManager->flush();
}
$this->entityManager->persist($uc);
$this->entityManager->flush();
$this->addFlash('success', 'Case assigned successfully');
return $this->redirectToRoute('app_list_cases');
}
return $this->render(
'internal/admin/cases/assign-case.html.twig',
array_merge(
$this->navLinks,
[
'title' => 'Assign Case',
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_list_cases'), 'List Cases'),
new Breadcrumb($this->generateUrl('app_assign_case', ['id' => $id]), 'Assign Case')
],
'notifications' => $admin->retrieveUnreadNotifications(),
'form' => $form,
'id' => $id,
'caseWorkers' => $caseWorkers,
'assignedWorkerId' => (count($case->getUserCases()) > 0 ? $case->getUserCases()->first()->getUser()->getId() : null),
]
)
);
}
#[Route('/api/filter-cases-by-user', name: 'ajax_filter_cases_by_user')]
public function filterCasesByUser(Request $request): Response
{
/** @var User $user */
$user = $this->entityManager->getRepository(User::class)->find($request->query->get('userId'));
/** @var UserCase[] $ucs */
$ucs = $this->entityManager->getRepository(UserCase::class)->findBy(['user' => $user]);
$ret = [];
foreach ($ucs as $uc) {
$ret[] = $uc->getMemberCase();
}
dump($ret);
die;
return $this->json($ret);
}
}

View File

@ -0,0 +1,227 @@
<?php
namespace App\Controller\Company;
use App\Entity\Company\Company;
use App\Entity\Company\CompanyDocument;
use App\Entity\System\User;
use App\Form\CompanyDocumentFormType;
use App\Form\InternalCompanyFormType;
use App\Libs\Breadcrumb;
use App\Libs\NavList;
use App\Libs\Libs;
use DateTime;
use DateTimeZone;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\String\Slugger\SluggerInterface;
class CompanyController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager,
private array $navLinks = []
){
$this->navLinks = NavList::LIST;
}
#[Route('/company', name: 'app_company')]
#[IsGranted(new Expression('is_granted("ROLE_ADMIN")'))]
public function editCompanyInfo(
#[CurrentUser()] User $user,
Request $request,
SluggerInterface $slugger
): Response {
$this->navLinks['company_nav'] = NavList::PRESENT_LINK;
$company = $user->getCompany();
$form = $this->createForm(InternalCompanyFormType::class, $company);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
/** @var Company $company */
$company = $form->getData();
if ($form->get('companyLogo')->getData()) {
$file = $form['companyLogo']->getData();
$destination = $this->getParameter('kernel.project_dir').'/public/uploads/company/';
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
$newFilename = $slugger->slug($originalFilename).'-'.uniqid().'.'.$file->guessExtension();
$file->move(
$destination,
$newFilename
);
$company->setCompanyLogo($newFilename);
}
$this->entityManager->flush();
return $this->redirectToRoute('app_admin_dashboard');
}
return $this->render(
'internal/admin/company/company-info.html.twig',
array_merge(
$this->navLinks,
[
'form' => $form,
'company' => $company,
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_admin_dashboard'), "Admin Dashboard"),
],
'msgs' => Libs::getMessages($user, $this->entityManager),
]
)
);
}
#[Route('/company/directory', name: 'app_company_directory')]
public function companyDirectory(#[CurrentUser()] User $user): Response
{
$this->navLinks['company_nav'] = NavList::PRESENT_LINK;
$users = $this->entityManager->getRepository(User::class)->findBy(['company' => $user->getCompany()], ['name' => 'ASC']);
return $this->render(
'internal/admin/company/directory.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb(
($this->isGranted('ROLE_ADMIN') ? $this->generateUrl('app_admin_dashboard') : $this->generateUrl('app_dashboard')),
($this->isGranted('ROLE_ADMIN') ? "Admin Dashboard" : "Dashboard")
),
],
'users' => $users,
'notifications' => Libs::getMessages($user, $this->entityManager),
]
)
);
}
#[Route('/user/download-vcard/{id}', name: 'app_download_user_vcard')]
public function downloadUserVcard(#[CurrentUser()] User $user, string $id): Response
{
$coworker = $this->entityManager->getRepository(User::class)->find($id);
if (!$coworker) {
throw new NotFoundHttpException('Coworker not found');
}
if ($coworker->getCompany() !== $user->getCompany()) {
throw new NotFoundHttpException('Coworker not found');
}
return new Response($coworker->generateVCard(), 200, [
'Content-Type' => 'text/vcf',
'Content-Disposition' => 'attachment; filename="' . str_replace(' ', '', $coworker->getName()) . '.vcf"',
'Content-Length' => strlen($coworker->generateVCard()),
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
'Expires' => '0',
'Pragma' => 'public',
'Content-Transfer-Encoding' => 'binary'
]);
}
#[Route('/docs/list', name: 'app_list_documents')]
#[IsGranted(new Expression('is_granted("ROLE_ADMIN")'))]
public function listDocs(#[CurrentUser()] User $user): Response
{
$this->navLinks['company_nav'] = NavList::PRESENT_LINK;
$companyDocs = $this->entityManager->getRepository(CompanyDocument::class)->findBy(['company' => $user->getCompany()], ['title' => 'ASC']);
return $this->render(
'internal/admin/company/docs/list-documents.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [],
'notifications' => Libs::getMessages($user, $this->entityManager),
'docs' => $companyDocs,
]
)
);
}
#[Route('/docs/add', name: 'app_add_doc')]
#[IsGranted(new Expression('is_granted("ROLE_ADMIN")'))]
public function addCompanyDocument(Request $request, #[CurrentUser()] User $user): Response
{
$this->navLinks['company_nav'] = NavList::PRESENT_LINK;
$form = $this->createForm(CompanyDocumentFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var CompanyDocument $doc */
$doc = $form->getData();
$doc->setCompany($user->getCompany());
$doc->setUpdated(new DateTime('now', new DateTimeZone($_ENV['COMPANY_TIMEZONE'])));
$this->entityManager->persist($doc);
$this->entityManager->flush();
return $this->redirectToRoute('app_list_documents');
}
return $this->render(
'internal/admin/company/docs/add-document.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [],
'notifications' => Libs::getMessages($user, $this->entityManager),
'form' => $form,
]
)
);
}
#[Route('/docs/edit/{docId}', name: 'app_edit_doc')]
#[IsGranted(new Expression('is_granted("ROLE_ADMIN")'))]
public function editCompanyDocument(string $docId, Request $request, #[CurrentUser()] User $user): Response
{
$companyDoc = $this->entityManager->getRepository(CompanyDocument::class)->find($docId);
$this->navLinks['company_nav'] = NavList::PRESENT_LINK;
checkdate(1, 1, 1);
$form = $this->createForm(CompanyDocumentFormType::class, $companyDoc);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var CompanyDocument $doc */
$doc = $form->getData();
$doc->setUpdated(new DateTime('now', new DateTimeZone($_ENV['COMPANY_TIMEZONE'])));
$this->entityManager->persist($doc);
$this->entityManager->flush();
return $this->redirectToRoute('app_list_documents');
}
return $this->render(
'internal/admin/company/docs/edit-document.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [],
'notifications' => Libs::getMessages($user, $this->entityManager),
'form' => $form,
'doc' => $companyDoc,
'docText' => str_replace("\r\n", "", $companyDoc->getText())
]
)
);
}
}

View File

@ -0,0 +1,82 @@
<?php
namespace App\Controller\Company;
use App\Entity\Company\CompanyDocument;
use App\Entity\Case\Member;
use App\Entity\Case\MemberDocument;
use App\Entity\System\User;
use App\Libs\Breadcrumb;
use App\Libs\NavList;
use App\Libs\Libs;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
class DocumentController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager,
private array $navLinks = []
) {
$this->navLinks = NavList::LIST;
}
#[Route('/member/{memberId}', name: 'app_display_case_doc')]
public function displayCaseDocument(string $memberId, #[CurrentUser()] User $user): Response
{
/** @var Member $member */
$member = $this->entityManager->getRepository(Member::class)->find($memberId);
$memberDocs = $this->entityManager->getRepository(MemberDocument::class)->findBy(['client' => $member]);
return $this->render(
'internal/cases/members/documents/list-member-docs.html.twig',
array_merge(
$this->navLinks,
[
'notifications' => Libs::getMessages($user, $this->entityManager),
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_my_cases'), 'Cases'),
new Breadcrumb($this->generateUrl('app_case_members', ['id' => $member->getCaseId()->getId()->toString()]), 'Members'),
],
'docs' => $memberDocs,
]
)
);
}
#[Route('/member/{memberId}/document/{docId}/sign', name: 'app_member_sign_case_doc')]
public function signCaseDocument(string $memberId, string $docId, #[CurrentUser()] User $user, Request $request): Response
{
/** @var Member $member */
$member = $this->entityManager->getRepository(Member::class)->find($memberId);
/** @var CompanyDocument $doc */
$doc = $this->entityManager->getRepository(CompanyDocument::class)->find($docId);
/** @var MemberDocument $memDoc */
$memDoc = $this->entityManager->getRepository(MemberDocument::class)->findOneBy([
'document' => $doc,
'client' => $member,
'caseWorker' => $user
]);
if (!$memDoc) {
throw new NotFoundHttpException('Document not found');
}
//$form = $this->createForm(MemberDocument::class);
/** @todo add form data */
//$form->add();
return $this->render(
'internal/cases/members/documents/sign-member-doc.html.twig', [
'doc' => $memDoc,
'caseWorkerSignature' => $user->getSignature(),
]
);
}
}

View File

@ -1,72 +0,0 @@
<?php
namespace App\Controller;
use App\Entity\User;
use App\Libs\NavList;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
class DefaultController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly UserPasswordHasherInterface $userPasswordHasher,
private array $navLinks = []
) {
$this->navLinks = NavList::LIST;
}
#[Route('/dashboard', name: 'app_dashboard')]
public function dashboard(Request $request, #[CurrentUser()] ?User $user): Response
{
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
if (!$user->getCompany()) {
return $this->redirectToRoute('app_register_step', ['step' => RegistrationController::REGISTER_STEP_TWO]);
}
$this->navLinks['user_dashboard'] = 'nav-link text-white active bg-gradient-dark';
return $this->render(
'internal/dashboard.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
'Dashboard'
],
'notifications' => $user->retrieveUnreadNotifications(),
]
)
);
}
#[Route('/profile', name: 'app_profile')]
public function profile(#[CurrentUser()] User $user): Response
{
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
$this->navLinks['profile'] = 'nav-link text-white active bg-gradient-dark';
return $this->render(
'internal/profile.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
'Profile'
],
'notifications' => $user->retrieveUnreadNotifications(),
]
)
);
}
}

View File

@ -1,185 +0,0 @@
<?php
namespace App\Controller;
use App\Entity\Member;
use App\Entity\User;
use App\Entity\MemberCase;
use App\Form\MemberFormType;
use App\Libs\Breadcrumb;
use App\Libs\NavList;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
class MemberController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager,
private array $navLinks = [],
) {
$this->navLinks = NavList::LIST;
}
#[Route('/list-members/{id}', name: 'app_case_members')]
public function listMembers(Request $request, #[CurrentUser()] User $user, string $id): Response
{
$case = $this->entityManager->getRepository(MemberCase::class)->find($id);
$members = $this->entityManager->getRepository(Member::class)->getCaseMembersByName($case);
return $this->render(
'internal/cases/members/list-members.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_case_list'), 'List Cases'),
new Breadcrumb($this->generateUrl('app_case_members', ['id' => $id]), 'List Members'),
],
'notifications' => $user->retrieveUnreadNotifications(),
'case' => $case,
'members' => $members,
]
)
);
}
#[Route('/add-member/{id}', name: 'app_case_add_member')]
public function addMember(Request $request, #[CurrentUser()] User $user, string $id): Response
{
/** @var MemberCase $case */
$case = $this->entityManager->getRepository(MemberCase::class)->find($id);
$member = new Member();
$form = $this->createForm(MemberFormType::class, $member);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$member->setCaseId($case)
->setFirstName($form->get('firstName')->getData())
->setLastName($form->get('lastName')->getData())
->setDob($form->get('dob')->getData())
->setGender($form->get('gender')->getData())
->setRace($form->get('race')->getData())
->setLanguage($form->get('language')->getData())
->setPersonalId($form->get('personalId')->getData())
->setEmergencyContact($form->get('emergencyContact')->getData())
->setEmail($form->get('email')->getData())
->setAddress($form->get('address')->getData())
->setCity($form->get('city')->getData())
->setState($form->get('state')->getData())
->setZip($form->get('zip')->getData())
->setPhone($form->get('phone')->getData())
->setRelationship($form->get('relationship')->getData())
->setDayPhone($form->get('dayPhone')->getData())
->setEveningPhone($form->get('eveningPhone')->getData())
->setCellPhone($form->get('cellPhone')->getData())
->setSchool($form->get('school')->getData())
->setMaritalStatus($form->get('maritalStatus')->getData())
->setChild($form->get('isChild')->getData())
->setParent($form->get('isParent')->getData())
->setAdultChild($form->get('isAdultChild')->getData())
->setLegalGuardian($form->get('isLegalGuardian')->getData())
->setParentsLiveTogether($form->get('parentsLiveTogether')->getData())
->setDcsApproved($form->get('dcsApproved')->getData())
;
$this->entityManager->persist($member);
$this->entityManager->flush();
$this->addFlash(
'success',
'Member added successfully'
);
return $this->redirectToRoute('app_case_members', ['id' => $case->getId()]);
}
return $this->render(
'internal/cases/members/add-member.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_case_list'), 'List Cases'),
new Breadcrumb($this->generateUrl('app_case_members', ['id' => $id]), 'List Members'),
new Breadcrumb($this->generateUrl('app_case_add_member', ['id' => $id]), 'Add Member'),
],
'notifications' => $user->retrieveUnreadNotifications(),
'case' => $case,
'form' => $form->createView(),
]
)
);
}
#[Route('/case/{caseId}/edit-member/{memberId}', name: 'app_case_edit_member')]
public function editMember(Request $request, #[CurrentUser()] User $user, string $caseId, string $memberId): Response
{
$member = $this->entityManager->getRepository(Member::class)->find($memberId);
$form = $this->createForm(MemberFormType::class, $member);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$member->setFirstName($form->get('firstName')->getData())
->setLastName($form->get('lastName')->getData())
->setDob($form->get('dob')->getData())
->setGender($form->get('gender')->getData())
->setRace($form->get('race')->getData())
->setLanguage($form->get('language')->getData())
->setPersonalId($form->get('personalId')->getData())
->setEmergencyContact($form->get('emergencyContact')->getData())
->setEmail($form->get('email')->getData())
->setAddress($form->get('address')->getData())
->setCity($form->get('city')->getData())
->setState($form->get('state')->getData())
->setZip($form->get('zip')->getData())
->setPhone($form->get('phone')->getData())
->setRelationship($form->get('relationship')->getData())
->setDayPhone($form->get('dayPhone')->getData())
->setEveningPhone($form->get('eveningPhone')->getData())
->setCellPhone($form->get('cellPhone')->getData())
->setSchool($form->get('school')->getData())
->setMaritalStatus($form->get('maritalStatus')->getData())
->setChild($form->get('isChild')->getData())
->setParent($form->get('isParent')->getData())
->setAdultChild($form->get('isAdultChild')->getData())
->setLegalGuardian($form->get('isLegalGuardian')->getData())
->setParentsLiveTogether($form->get('parentsLiveTogether')->getData())
->setDcsApproved($form->get('dcsApproved')->getData())
;
$this->entityManager->flush();
$this->addFlash(
'success',
'Member updated successfully'
);
return $this->redirectToRoute('app_case_members', ['id' => $caseId]);
}
return $this->render(
'internal/cases/members/edit-member.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_case_list'), 'List Cases'),
new Breadcrumb($this->generateUrl('app_case_members', ['id' => $caseId]), 'List Members'),
new Breadcrumb($this->generateUrl('app_case_edit_member', ['caseId' => $caseId, 'memberId' => $memberId]), 'Edit Member'),
],
'notifications' => $user->retrieveUnreadNotifications(),
'member' => $member,
'form' => $form->createView(),
'caseId' => $caseId,
]
)
);
}
}

View File

@ -0,0 +1,205 @@
<?php
namespace App\Controller\Resources;
use App\Entity\Resources\CommunityResource;
use App\Entity\System\User;
use App\Form\ResourceFormType;
use App\Libs\Breadcrumb;
use App\Libs\Libs;
use App\Libs\NavList;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
use Symfony\UX\Map\InfoWindow;
use Symfony\UX\Map\Map;
use Symfony\UX\Map\Marker;
use Symfony\UX\Map\Point;
class CommunityResourceController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private array $navLinks = []
) {
$this->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' => Libs::getMessages($user, $this->entityManager),
]
)
);
}
#[Route('/resource/map', name: 'app_community_resource_map')]
public function map(#[CurrentUser()] User $user): Response
{
$rcs = $this->entityManager->getRepository(CommunityResource::class)->findAll();
$map = new Map('default');
$map->center(new Point($_ENV['MAP_CENTER_LAT'], $_ENV['MAP_CENTER_LON']))
->zoom($_ENV['MAP_ZOOM_LEVEL'])
;
foreach ($rcs as $rsc) {
/** @var CommunityResource $rsc */
$map->addMarker(new Marker(
position: new Point($rsc->getLat(), $rsc->getLon()),
title: $rsc->getName(),
infoWindow: new InfoWindow(
content: $rsc->_toInfoWindow()
),
extra: [
'type' => ''
]
));
}
return $this->render(
'internal/community_resource/map.html.twig',
array_merge(
$this->navLinks,
[
'map' => $map,
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_community_resource'), 'List Resources'),
new Breadcrumb('#', 'Community Resources')
],
'notifications' => Libs::getMessages($user, $this->entityManager),
]
)
);
}
#[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()) {
/** @var CommunityResource $rsc */
$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->flush();
$this->addFlash('success', 'Resource added successfully');
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' => Libs::getMessages($user, $this->entityManager),
]
)
);
}
#[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()) {
$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->addFlash('success', 'Resource updated successfully');
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' => Libs::getMessages($user, $this->entityManager),
]
)
);
}
#[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'
]);
}
}

View File

@ -0,0 +1,439 @@
<?php
namespace App\Controller\Staff;
use App\Entity\Case\MemberCase;;
use App\Entity\Staff\StaffNote;
use App\Entity\Staff\Supervision;
use App\Entity\System\User;
use App\Entity\System\UserCase;
use App\Factory\MessageFactory;
use App\Form\StaffNoteFormType;
use App\Form\SupervisorStaffNoteFormType;
use App\Libs\Breadcrumb;
use App\Libs\Libs;
use App\Libs\NavList;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
use Symfony\Component\Translation\Exception\NotFoundResourceException;
class StaffController extends AbstractController
{
/**
* Variable to store unread notification messages
*
* @var array <int, Message>
*/
private array $msgs;
public function __construct(
private readonly EntityManagerInterface $entityManager,
private array $navLinks = []
) {
$this->navLinks = NavList::LIST;
$this->navLinks['staff_dashboard'] = NavList::PRESENT_LINK;
}
#[Route('/staff-dashboard', name: 'app_staff_dashboard')]
public function staffDashboard(#[CurrentUser()] User $user): Response
{
$this->msgs = Libs::getMessages($user, $this->entityManager);
$sups = $this->entityManager->getRepository(Supervision::class)->findBy(['supervisor' => $user]);
$staff = [];
foreach ($sups as $sup) {
$staff[] = $sup->getWorker();
}
return $this->render(
'internal/staff/staff-dashboard.html.twig',
array_merge(
$this->navLinks,
[
'staff' => $staff,
'breadcrumbs' => [
new Breadcrumb('', 'Staff Dashboard')
],
'notifications' => $this->msgs,
]
)
);
}
#[Route('/staff/my-cases', name:'app_staff_my_cases')]
public function staffMyCases(#[CurrentUser()] User $user): Response
{
if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$this->navLinks['staff_dashboard'] = NavList::DEFAULT;
$this->navLinks['staff_notes'] = NavList::PRESENT_LINK;
$this->msgs = Libs::getMessages($user, $this->entityManager);
$sup = $this->entityManager->getRepository(Supervision::class)->findOneBy(['worker' => $user]);
$ucs = $this->entityManager->getRepository(UserCase::class)->findBy(['user' => $user]);
$cases = [];
$this->navLinks['staff_dashboard'] = 'nav-link text-dark';
$this->navLinks['staff_notes'] = NavList::PRESENT_LINK;
foreach ($ucs as $uc) {
$case = $uc->getMemberCase();
$lastNote = $this->entityManager->getRepository(StaffNote::class)->findOneBy(['memberCase' => $case], ['date' => 'DESC']);
if ($lastNote) {
$case->emptyStaffNotes();
$case->addStaffNote($lastNote);
}
$cases[] = $case;
}
return $this->render(
'internal/staff/cases/my-cases.html.twig',
array_merge(
$this->navLinks,
[
'cases' => $cases,
'user' => $user,
'supervisor' => $sup->getSupervisor(),
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_staff_dashboard'), 'Staff Dashboard'),
new Breadcrumb('', 'Staff Cases')
],
'notifications' => $this->msgs,
]
)
);
}
#[Route('/staff/{staffId}', name: 'app_staff_cases')]
public function staffCases(string $staffId, #[CurrentUser()] User $user): Response
{
if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$staff = $this->entityManager->getRepository(User::class)->find($staffId);
$sup = $this->entityManager->getRepository(Supervision::class)->findOneBy(['worker' => $staff, 'supervisor' => $user]);
if (!$sup) {
throw new NotFoundResourceException("It does not appear you are the supervisor to this case worker");
}
$ucs = $this->entityManager->getRepository(UserCase::class)->findBy(['user' => $staff]);
$cases = [];
foreach ($ucs as $uc) {
/** @var MemberCase $case */
$case = $uc->getMemberCase();
$lastNote = $this->entityManager->getRepository(StaffNote::class)->findOneBy(['memberCase' => $case], ['date' => 'DESC']);
if ($lastNote) {
$case->emptyStaffNotes();
$case->addStaffNote($lastNote);
}
$cases[] = $case;
}
return $this->render(
'internal/staff/cases/staff-cases.html.twig',
array_merge(
$this->navLinks,
[
'staffId' => $staffId,
'cases' => $cases,
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_staff_dashboard'), 'Staff Dashboard'),
new Breadcrumb('', 'Staff Cases')
],
'notifications' => Libs::getMessages($user, $this->entityManager),
]
)
);
}
#[Route('/staff/{staffId}/case/{caseId}/list-notes', name: 'app_staff_list_notes')]
public function staffListNotes(string $staffId, string $caseId, #[CurrentUser()] User $user): Response
{
if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$this->msgs = Libs::getMessages($user, $this->entityManager);
$this->navLinks['staff_dashboard'] = NavList::DEFAULT;
$this->navLinks['staff_notes'] = NavList::PRESENT_LINK;
$isWorker = ($staffId == $user->getId()->toString());
$staff = $this->entityManager->getRepository(User::class)->find($staffId);
$case = $this->entityManager->getRepository(MemberCase::class)->find($caseId);
$staffNotes = $this->entityManager->getRepository(StaffNote::class)->getOrderedNotes($case);
return $this->render(
'internal/staff/notes/list-notes.html.twig',
array_merge(
$this->navLinks,
[
'isWorker' => $isWorker,
'staffId' => $staffId,
'staff' => $staff,
'case' => $case,
'staffNotes' => $staffNotes,
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_staff_dashboard'), 'Staff Dashboard'),
new Breadcrumb(
$this->generateUrl(
($staffId == $user->getId()->toHex() ? 'app_staff_my_cases' : 'app_staff_cases'),
['staffId' => $staffId]
),
($staffId == $user->getId()->toHex() ? 'My Cases' : 'Staff Cases')
),
new Breadcrumb('', 'List Notes')
],
'notifications' => $this->msgs,
]
)
);
}
#[Route('/staff/add-note/{caseId}', name: 'app_staff_add_note')]
public function addNote(string $caseId, #[CurrentUser()] User $user, Request $request): Response
{
if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$this->msgs = Libs::getMessages($user, $this->entityManager);
$this->navLinks['staff_dashboard'] = NavList::DEFAULT;
$this->navLinks['staff_notes'] = NavList::PRESENT_LINK;
$case = $this->entityManager->getRepository(MemberCase::class)->find($caseId);
$form = $this->createForm(StaffNoteFormType::class);
$this->navLinks['staff_dashboard'] = 'nav-link text-dark';
$this->navLinks['staff_notes'] = NavList::PRESENT_LINK;
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var StaffNote $note */
$note = $form->getData();
$note->setMemberCase($case);
/** @var Supervision $sup */
$sup = $this->entityManager->getRepository(Supervision::class)->findOneBy(['worker' => $user]);
$msg = MessageFactory::createStaffing($user, $sup->getSupervisor());
$this->entityManager->persist($note);
$this->entityManager->persist($msg);
$this->entityManager->flush();
$msg->setLink("/staff/sup-sign-note/" . $note->getId());
$this->entityManager->persist($msg);
$this->entityManager->flush();
$this->addFlash('info', 'Staff note added');
return $this->redirectToRoute(
'app_staff_list_notes',
[
'staffId' => $user->getId()->toString(),
'caseId' => $caseId
]
);
}
return $this->render(
'internal/staff/notes/add-note.html.twig',
array_merge(
$this->navLinks,
[
'case' => $case,
'form' => $form,
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_staff_dashboard'), 'Staff Dashboard'),
new Breadcrumb($this->generateUrl('app_staff_list_notes', ['staffId' => $user->getId()->toHex(), 'caseId' => $caseId]), 'My Cases'),
new Breadcrumb('', 'Add Note'),
],
'notifications' => $this->msgs,
]
)
);
}
#[Route('/staff/edit-note/{noteId}', name: 'app_staff_edit_note')]
public function editNote(string $noteId, #[CurrentUser()] User $user, Request $request): Response
{
if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->redirectToRoute('app_login');
}
$this->msgs = Libs::getMessages($user, $this->entityManager);
$this->navLinks['staff_dashboard'] = NavList::DEFAULT;
$this->navLinks['staff_notes'] = NavList::PRESENT_LINK;
$note = $this->entityManager->getRepository(StaffNote::class)->find($noteId);
$case = $note->getMemberCase();
if ($note->getSupervisorSignDateTime() || $note->getWorkerSignDateTime()) {
$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);
if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->flush();
$this->addFlash('info', 'Staff notes updated');
$this->redirectToRoute('app_staff_list_notes', ['staffId' => $user->getId()->toString(), 'caseId' => $case->getId()->toString()]);
}
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,
]
)
);
}
#[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 = Libs::getMessages($user, $this->entityManager);
$this->navLinks['staff_dashboard'] = NavList::DEFAULT;
$this->navLinks['staff_notes'] = NavList::PRESENT_LINK;
$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,
]
)
);
}
#[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 = Libs::getMessages($user, $this->entityManager);
$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(['memberCase' => $case]);
$msg = MessageFactory::createSupervisorSignStaffNote($user, $uc->getUser(), $case);
$msg->setLink('/staff/sign-my-note/' . $note->getId());
$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,
]
)
);
}
#[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 = Libs::getMessages($user, $this->entityManager);
$this->navLinks['staff_dashboard'] = NavList::DEFAULT;
$this->navLinks['staff_notes'] = NavList::PRESENT_LINK;
$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,
]
)
);
}
}

View File

@ -1,43 +0,0 @@
<?php
namespace App\Controller;
use App\Entity\User;
use App\Libs\Breadcrumb;
use App\Libs\NavList;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
class StaffController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly UserPasswordHasherInterface $userPasswordHasher,
private array $navLinks = []
) {
$this->navLinks = NavList::LIST;
}
#[Route('/staff-dashboard', name: 'app_staff_dashboard')]
public function staffDashboard(#[CurrentUser()] User $user): Response
{
$this->navLinks['staff_dashboard'] = 'nav-link text-white active bg-gradient-dark';
return $this->render(
'internal/staff/staff-dashboard.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb('', 'Staff Dashboard')
],
'notifications' => $user->retrieveUnreadNotifications(),
]
)
);
}
}

View File

@ -0,0 +1,274 @@
<?php
namespace App\Controller\System;
use App\Entity\Case\CaseItinerary;
use App\Entity\Case\CaseLocation;
use App\Entity\Resources\CommunityResource;
use App\Entity\Case\MemberCase;;
use App\Entity\Case\Referral;
use App\Entity\Case\StandardNote;
use App\Entity\Case\StandardNoteMember;
use App\Entity\System\Location;
use App\Entity\System\User;
use App\Entity\System\UserCase;
use App\Entity\Case\VisitNote;
use App\Entity\Case\VisitNoteMembers;
use App\Libs\Libs;
use DateTime;
use DateTimeZone;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
class AjaxController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager,
) {
}
#[Route('/api/itinerary/{id}/add', name: 'ajax_itinerary_add')]
public function addItinerary(string $id, Request $request): Response
{
$itinerary = $this->entityManager->getRepository(UserCase::class)->find($id);
$data = json_decode($request->getContent());
$location = new Location();
//$location->setItinerary($itinerary)
;
return $this->json($location);
}
#[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, #[CurrentUser()] User $admin) : Response
{
$ret = true;
$user = $this->entityManager->getRepository(User::class)->find($userId);
$case = $this->entityManager->getRepository(MemberCase::class)->find($caseId);
if (!Libs::checkPermissions($user, $case, $this->entityManager)) {
throw new AccessDeniedHttpException ('You do not have permission to access this resource.');
}
$res = UserCase::checkLevel($admin, $case);
if (!$res) {
$ret = [
'userLevel' => ucwords(str_replace('_', ' ', strtolower($user->getLevel()->name))),
'caseLevel' => ucwords(str_replace('_', ' ', strtolower($case->getLevel()->name))),
];
}
return $this->json($ret);
}
#[Route('/api/filter-cases-by-user', name: 'ajax_filter_cases_by_user')]
public function filterCasesByUser(Request $request): Response
{
/** @var User $user */
$user = $this->entityManager->getRepository(User::class)->find($request->query->get('userId'));
/** @var UserCase[] $ucs */
$ucs = $this->entityManager->getRepository(UserCase::class)->findBy(['user' => $user]);
$ret = [];
foreach ($ucs as $uc) {
$ret[] = $uc->getMemberCase();
}
return $this->json($ret);
}
#[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'];
if ($county) {
$resources = $this->entityManager->getRepository(CommunityResource::class)->findBy(['county' => $county]);
} else {
$resources = $this->entityManager->getRepository(CommunityResource::class)->findAll();
}
return $this->json($resources);
}
#[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);
$crs = $this->entityManager->getRepository(CommunityResource::class)->findAll();
$locations = [];
foreach ($cls as $cl) {
/** @var CaseLocation $cl */
$locations[] = $cl->getLocation();
}
foreach ($crs as $cr) {
$locations[] = $cr->toLocation();
}
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');
$caseMileage = (bool) $request->getPayload()->get('caseMileage');
$date = new DateTime($request->getPayload()->get('date'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']));
$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))
->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'
]);
}
#[Route('/api/filter-itinerary-by-case', name: 'ajax_filter_itinerary_by_case')]
public function filterItineraryByCase(Request $request, #[CurrentUser()] ?User $user): Response
{
$case = null;
$startDate = null;
$endDate = null;
//dd($request->getPayload());
if ($request->getPayload()->get('caseId')) {
$caseId = $request->getPayload()->get('caseId');
$case = $this->entityManager->getRepository(MemberCase::class)->find($caseId);
}
if ($request->getPayload()->get('startDate')) {
$startDate = new DateTime($request->getPayload()->get('startDate'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']));
}
if ($request->getPayload()->get('endDate')) {
$endDate = new DateTime($request->getPayload()->get('endDate'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']));
}
$itineraries = $this->entityManager->getRepository(CaseItinerary::class)->getRecentTravel($user, [
'case' => $case,
'from' => $startDate,
'to' => $endDate,
]);
$ret = [];
foreach ($itineraries as $itinerary) {
/** @var CaseItinerary $itinerary */
$ret[] = [
'id' => $itinerary->getId()->toString(),
'date' => $itinerary->getDate()->format('F j, Y'),
'origin' => $itinerary->getOriginLocation(),
'destination' => $itinerary->getDestLocation(),
'distance' => $itinerary->getDistance(),
'duration' => $itinerary->getDuration()->format("%h:%i'%s''"),
'case' => $itinerary->getMemberCase()->getCaseName(),
];
}
return $this->json($ret);
}
#[Route('/api/filter-notes', name: 'api_filter_notes')]
public function filterNotes(#[CurrentUser()] User $user, Request $request): Response
{
$startDate = null;
$endDate = null;
$referral = null;
$case = null;
if ($request->getPayload()->get('startDate')) {
$startDate = new DateTime($request->getPayload()->get('startDate'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']));
}
if ($request->getPayload()->get('endDate')) {
$endDate = new DateTime($request->getPayload()->get('endDate'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']));
}
if ($request->getPayload()->get('referral')) {
$referral = $this->entityManager->getRepository(Referral::class)->find($request->getPayload()->get('referral'));
}
if ($request->getPayload()->get('case')) {
$case = $this->entityManager->getRepository(MemberCase::class)->find($request->getPayload()->get('case'));
}
$params = [
'startDate' => $startDate,
'endDate' => $endDate,
'referral' => $referral,
'case' => $case,
];
$notes = array_merge(
$this->entityManager->getRepository(VisitNote::class)->filterNotes($user, $params),
$this->entityManager->getRepository(StandardNote::class)->filterNotes($user, $params),
);
foreach ($notes as $idx => $note) {
/** @var VisitNote|StandardNote $note */
/** @var VisitNoteMember[]|StandardNoteMember[] $members */
if ($note instanceof VisitNote) {
$members = $this->entityManager->getRepository(VisitNoteMembers::class)->findBy(['note' => $note]);
} elseif ($note instanceof StandardNote) {
$members = $this->entityManager->getRepository(StandardNoteMember::class)->findBy(['note' => $note]);
} else {
continue;
}
$notes[$idx]->setMembers($members);
}
return new Response(json_encode($notes, 0, 3));
}
}

View File

@ -0,0 +1,237 @@
<?php
namespace App\Controller\System;
use App\Entity\System\User;
use App\Libs\Breadcrumb;
use App\Libs\Dashboard;
use App\Libs\Libs;
use App\Libs\NavList;
use DateInterval;
use DateTime;
use DateTimeInterface;
use DateTimeZone;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TelType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
use Symfony\Component\String\Slugger\SluggerInterface;
class DefaultController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly UserPasswordHasherInterface $userPasswordHasher,
private array $navLinks = []
) {
$this->navLinks = NavList::LIST;
}
#[Route('/up', name: 'app_up')]
public function up(): Response
{
$cnx = $this->entityManager->getConnection();
$cnx->connect();
$connected = $cnx->isConnected();
if ($connected) {
return $this->json(true, Response::HTTP_OK);
} else {
return $this->json(false, Response::HTTP_SERVICE_UNAVAILABLE);
}
}
#[Route('/dashboard', name: 'app_dashboard')]
public function dashboard(Request $request, #[CurrentUser()] ?User $user): Response
{
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
if (!$user->getCompany()) {
return $this->redirectToRoute('app_register_step', ['step' => RegistrationController::REGISTER_STEP_TWO]);
}
$oldPasswordDate = new DateTime('now', new DateTimeZone($_ENV['COMPANY_TIMEZONE']));
$oldPasswordDate->sub(DateInterval::createFromDateString('120 days'));
if (is_a($user->getPasswordChanged(), DateTimeInterface::class) && $user->getPasswordChanged() < $oldPasswordDate) {
$this->addFlash('danger', 'You must change your password');
return $this->redirectToRoute('app_profile');
}
if(isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] == "{$_SERVER['HTTP_X_FORWARDED_PROTO']}://{$_SERVER['HTTP_HOST']}/") {
$this->entityManager->getRepository(User::class)->updateLastLogin($user);
}
$dashboard = new Dashboard($this->entityManager, $user);
$this->navLinks['user_dashboard'] = NavList::PRESENT_LINK;
return $this->render(
'internal/dashboard.html.twig',
array_merge(
$this->navLinks,
$dashboard->toArray(),
[
'breadcrumbs' => [
new Breadcrumb('', 'Dashboard')
],
'notifications' => Libs::getMessages($user, $this->entityManager),
]
)
);
}
#[Route('/profile', name: 'app_profile')]
public function profile(
Request $request,
#[CurrentUser()] User $user,
SluggerInterface $slugger
): Response {
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
$this->navLinks['profile'] = NavList::PRESENT_LINK;
$form = $this->createFormBuilder($user)
->add('name', TextType::class, [
'label' => 'Name',
'label_attr' => ['class' => 'form-label'],
'attr' => ['class' => 'form-control'],
])
->add('email', EmailType::class, [
'label' => 'Email',
'label_attr' => ['class' => 'form-label'],
'attr' => ['class' => 'form-control'],
])
->add('password', RepeatedType::class, [
'type' => PasswordType::class,
'invalid_message' => 'The password fields must match.',
'required' => false,
'mapped' => false,
'first_options' => ['label' => 'Password', 'label_attr' => ['class' => 'form-label']],
'second_options' => ['label' => 'Repeat Password', 'label_attr' => ['class' => 'form-label']],
])
->add('personalPhone', TelType::class, [
'label' => 'Personal Phone',
])
->add('workPhone', TelType::class, [
'label' => 'Work Phone',
])
->add('imageName', FileType::class, [
'label' => 'Profile Picture',
'required' => false,
'mapped' => false
])
->add('signature', HiddenType::class)
->add('submit', SubmitType::class, [
'label' => 'Save Profile',
'attr' => ['class' => 'btn btn-lg bg-gradient-dark btn-lg w-100 mt-4 mb-0']
])
->getForm()
;
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if ($form->get('signature')->getData()) {
$signature = $form->get('signature')->getData();
$user->setSignature($signature);
}
$firstPassword = $form->get('password')['first']->getData();
$secondPassword = $form->get('password')['second']->getData();
if ($firstPassword !== $secondPassword) {
$this->addFlash('danger', 'The password fields must match.');
return $this->redirectToRoute('app_profile');
}
$plainPassword = $form->get('password')['first']->getData();
if ($plainPassword) {
$user->setPassword(
$this->userPasswordHasher->hashPassword(
$user,
$plainPassword
)
);
$user->setPasswordChanged(new DateTime('now', new DateTimeZone($_ENV['COMPANY_TIMEZONE'])));
}
if ($form['imageName']->getData()) {
/** @var \Symfony\Component\HttpFoundation\File\UploadedFile $file */
$file = $form['imageName']->getData();
$destination = $this->getParameter('kernel.project_dir').'/public/uploads/user_images/';
if (!file_exists($destination)) {
mkdir($destination, 0775);
}
$originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
$newFilename = $slugger->slug($originalFilename).'-'.uniqid().'.'.$file->guessExtension();
$file->move(
$destination,
$newFilename
);
$user->setImageName($newFilename);
}
if ($form['personalPhone']->getData()) {
$phone = Libs::Phone($form['personalPhone']->getData());
$user->setPersonalPhone($phone);
}
if ($form['workPhone']->getData()) {
$phone = Libs::Phone($form['workPhone']->getData());
$user->setWorkPhone($phone);
}
$this->entityManager->persist($user);
$this->entityManager->flush();
return $this->redirectToRoute('app_dashboard');
} elseif ($form->isSubmitted() && !$form->isValid()) {
$this->addFlash('danger', 'The form contains errors.');
}
return $this->render(
'internal/profile.html.twig',
array_merge(
$this->navLinks,
[
'breadcrumbs' => [
new Breadcrumb('', 'Profile')
],
'notifications' => Libs::getMessages($user, $this->entityManager),
'currentUser' => $user,
'signaturePresent' => ($user->getSignature() ? true : false),
'signature' => $user->getSignature(),
'form' => $form->createView(),
]
)
);
}
#[Route('/uploads/user_images/{imageName}', name: 'app_user_profile_image')]
public function displayUserImage(string $imageName): Response
{
return new BinaryFileResponse("{$this->getParameter('kernel.project_dir')}/public/{$_ENV['USER_IMAGE_PATH']}/{$imageName}");
}
#[Route('/uploads/company_images/{companyLogo}', name: 'app_company_logo')]
public function displayCompanyLogo(string $companyLogo): Response
{
return new BinaryFileResponse("{$this->getParameter('kernel.project_dir')}/public/{$_ENV['COMPANY_IMAGE_PATH']}/{$companyLogo}");
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace App\Controller\System;
use App\Entity\System\Messages;
use App\Entity\Staff\Supervision;
use App\Entity\System\User;
use App\Enums\System\MessageType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
class MessageController extends AbstractController
{
public function __construct(
private EntityManagerInterface $entityManager
) {
}
#[Route('/api/notifications/{msgId}', name: 'app_read_message')]
public function readMessage(string $msgId): Response
{
/** @var Messages $message */
$message = $this->entityManager->getRepository(Messages::class)->find($msgId);
$message->setReceived(new \DateTimeImmutable());
$this->entityManager->flush();
return $this->json([
'success' => true,
'message' => 'Message marked as read',
'link' => $message->getLink(),
]);
}
#[Route('/api/send-message', name: 'app_send_message')]
public function sendMessage(Request $request, #[CurrentUser()] User $user): Response
{
$sup = $this->entityManager->getRepository(Supervision::class)->getSupervisorByWorker($user);
$data = json_decode($request->getContent(), true);
$message = new Messages();
$message->setSender($user);
$message->setSent(new \DateTimeImmutable());
$message->setRecipient($sup);
$message->setTitle('New Message');
$message->setMessage($data['message']);
$message->setType(MessageType::GENERAL);
$this->entityManager->persist($message);
$this->entityManager->flush();
return $this->json([
'success' => true,
'message' => 'Message sent',
]);
}
}

View File

@ -1,11 +1,12 @@
<?php
namespace App\Controller;
namespace App\Controller\System;
use App\Entity\ReferralSource;
use App\Entity\User;
use App\Entity\System\ReferralSource;
use App\Entity\System\User;
use App\Form\ReferralSourceFormType;
use App\Libs\Breadcrumb;
use App\Libs\Libs;
use App\Libs\NavList;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@ -16,19 +17,27 @@ use Symfony\Component\Security\Http\Attribute\CurrentUser;
class ReferralSourceController extends AbstractController
{
/**
* Variable to store unread notification messages
*
* @var array
*/
private array $msgs;
public function __construct(
private EntityManagerInterface $entityManager,
private array $navList = []
) {
$this->navList = NavList::LIST;
$this->navList['referral_sources'] = NavList::PRESENT_LINK;
}
#[Route('/list-referral-sources', name: 'app_referral_source')]
public function listReferralSources(#[CurrentUser()] User $user): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$this->navList['referral_sources'] = 'nav-link text-white active bg-gradient-dark';
$this->msgs = Libs::getMessages($user, $this->entityManager);
$sources = $this->entityManager->getRepository(ReferralSource::class)->retrieveOrderedList();
return $this->render(
@ -37,7 +46,7 @@ class ReferralSourceController extends AbstractController
$this->navList,
[
'sources' => $sources,
'notifications' => $user->retrieveUnreadNotifications(),
'notifications' => $this->msgs,
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_referral_source'), 'Referral Sources')
]
@ -50,8 +59,8 @@ class ReferralSourceController extends AbstractController
public function addSource(Request $request, #[CurrentUser()] User $user): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$this->navList['referral_sources'] = 'nav-link text-white active bg-gradient-dark';
$this->msgs = Libs::getMessages($user, $this->entityManager);
$rs = new ReferralSource();
$form = $this->createForm(ReferralSourceFormType::class, $rs);
@ -74,7 +83,7 @@ class ReferralSourceController extends AbstractController
$this->navList,
[
'form' => $form,
'notifications' => $user->retrieveUnreadNotifications(),
'notifications' => $this->msgs,
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_referral_source'), 'Referral Sources'),
new Breadcrumb($this->generateUrl('app_add_source'), 'Add Source')
@ -88,8 +97,8 @@ class ReferralSourceController extends AbstractController
public function editSource(Request $request, #[CurrentUser()] User $user, string $id): Response
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
$this->navList['referral_sources'] = 'nav-link text-white active bg-gradient-dark';
$this->msgs = Libs::getMessages($user, $this->entityManager);
$rs = $this->entityManager->getRepository(ReferralSource::class)->find($id);
$form = $this->createForm(ReferralSourceFormType::class, $rs);
@ -113,7 +122,7 @@ class ReferralSourceController extends AbstractController
[
'form' => $form,
'rs' => $rs,
'notifications' => $user->retrieveUnreadNotifications(),
'notifications' => $this->msgs,
'breadcrumbs' => [
new Breadcrumb($this->generateUrl('app_referral_source'), 'Referral Sources'),
new Breadcrumb($this->generateUrl('app_edit_source', ['id' => $id]), 'Edit Source')

View File

@ -1,12 +1,11 @@
<?php
namespace App\Controller;
namespace App\Controller\System;
use App\DataTransferObject\CompanyDetailsDto;
use App\Entity\User;
use App\Enums\CaseLevel;
use App\Enums\JobType;
use App\Enums\RateType;
use App\Entity\System\User;
use App\Enums\Case\CaseLevel;
use App\Enums\System\RateType;
use App\Factory\CompanyFactory;
use App\Form\CompanyFormType;
use App\Form\RegistrationFormType;
@ -80,11 +79,7 @@ class RegistrationController extends AbstractController
)
);
$user->setCaseWorker(true)
->setCaseManager(true)
->setTherapist(true)
->setSu(true)
->setRateType(RateType::FIXED)
$user->setRateType(RateType::FIXED)
->setRate('0.00')
->setRoles(['ROLE_ADMIN'])
->setLevel(CaseLevel::ADMIN);

View File

@ -1,6 +1,6 @@
<?php
namespace App\Controller;
namespace App\Controller\System;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;

View File

@ -0,0 +1,17 @@
<?php
namespace App\DataFixtures;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
class AppFixtures extends Fixture
{
public function load(ObjectManager $manager): void
{
// $product = new Product();
// $manager->persist($product);
$manager->flush();
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace App\DataFixtures;
use App\Entity\Case\MemberCase;;
use App\Entity\System\ReferralSource;
use App\Entity\System\User;
use App\Entity\System\UserCase;
use App\Enums\Case\CaseLevel;
use App\Enums\System\County;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
class MemberCaseFixture extends Fixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{
if(!$_ENV['CREATE_CASES']) {
return;
}
$sources = $manager->getRepository(ReferralSource::class)->findAll();
$users = $manager->getRepository(User::class)->findAll();
$gen = \Faker\Factory::create();
for ($x = 0; $x < $_ENV['CREATE_CASES']; $x++) {
$case = new MemberCase();
$case->setCaseNumber($gen->numberBetween(1000000, 9999999))
->setDcsCaseId($gen->numberBetween(1000000, 9999999))
->setFirstName($gen->firstName())
->setLastName($gen->lastName())
->setCounty($gen->randomElement(County::class))
->setReferralSource($gen->randomElement($sources))
->setLevel($gen->randomElement(CaseLevel::class))
->setAdmitDate($gen->dateTimeBetween('-1 year', 'now'))
->setReferralType('DCS')
;
$uc = new UserCase();
$uc->setMemberCase($case);
$uc->setUser($gen->randomElement($users));
print "Adding member case {$case->getCaseNumber()}".PHP_EOL;
$manager->persist($case);
$manager->persist($uc);
}
$manager->flush();
}
public function getDependencies(): array
{
return [
ReferralSourceFixture::class,
UserFixture::class,
];
}
}

View File

@ -0,0 +1,85 @@
<?php
namespace App\DataFixtures;
use App\Entity\Case\Member;
use App\Entity\Case\MemberCase;;
use App\Enums\System\GenderType;
use App\Enums\Case\RaceType;
use App\Enums\Case\RelationshipType;
use App\Enums\System\State;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
class MemberFixture extends Fixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{
if (!$_ENV['CREATE_MEMBERS']) {
return;
}
$gen = \Faker\Factory::create();
$cases = $manager->getRepository(MemberCase::class)->findAll();
foreach ($cases as $case) {
/** @var MemberCase $case */
$caseLastName = $case->getLastName();
print "Adding members for case {$case->getCaseName()}".PHP_EOL;
$memCount = $gen->numberBetween(0, $_ENV['CREATE_MEMBERS']);
for ($x = 0; $x < $memCount; $x++) {
$isChild = $gen->boolean();
$isParent = ($isChild ? false : $gen->boolean());
$isLegalGuardian = (!$isParent && !$isChild ? $gen->boolean() : false);
$dcsApproved = (!$isParent && !$isChild ? $gen->boolean() : false);
$sameLastName = $gen->boolean();
$mem = new Member();
$name = $gen->firstName().' '.$gen->lastName();
$username = strtolower(str_replace(' ', '.', $name));
$phone = substr(str_replace(['-', '+', ' ', '(', ')'], '', $gen->e164PhoneNumber()), -10);
$mem->setRelationship($gen->randomElement(RelationshipType::class))
->setPersonalId($gen->numberBetween(1000000, 9999999))
->setGender($gen->randomElement(GenderType::class))
->setRace($gen->randomElement(RaceType::class))
->setPhone($phone)
->setCellPhone($phone)
->setEmail($username.'@'.$gen->freeEmailDomain())
->setAddress($gen->streetAddress())
->setCity($gen->city())
->setState(State::IN->name)
->setZip($gen->postcode())
->setDob(
$gen->dateTimeBetween(
($isChild ? '-16 years' : '-50 years'),
($isParent || $isLegalGuardian ? '-16 years' : '-1 month')
)
)
->setFirstName($gen->firstName())
->setLastName($sameLastName ? $caseLastName : $gen->lastName())
->setChild($isChild)
->setParent($isParent)
->setLegalGuardian($isLegalGuardian)
->setAdultChild(false)
->setParentsLiveTogether(false)
->setDcsApproved($dcsApproved)
->setCaseId($case)
;
print "Adding member {$mem->getFirstName()} {$mem->getLastName()}".PHP_EOL;
$manager->persist($mem);
}
}
$manager->flush();
}
public function getDependencies(): array
{
return [
MemberCaseFixture::class,
ReferralFixture::class,
];
}
}

View File

@ -0,0 +1,112 @@
<?php
namespace App\DataFixtures;
use App\Entity\Case\MemberCase;;
use App\Entity\Case\Referral;
use App\Entity\Case\StandardNote;
use App\Entity\Case\VisitNote;
use App\Enums\Case\NoteLocation;
use App\Enums\Case\NoteMethod;
use App\Enums\Case\NoteStatus;
use App\Enums\Case\ReferralServiceType;
use App\Enums\Case\VisitQualityLevel;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
class NoteFixture extends Fixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{
if(!$_ENV['CREATE_NOTES']) {
return;
}
$gen = \Faker\Factory::create();
$refs = $manager->getRepository(Referral::class)->findAll();
foreach ($refs as $ref) {
/** @var Referral $ref */
print "Adding notes for referral {$ref->getReferralId()}".PHP_EOL;
$noteCount = $gen->numberBetween(0, $_ENV['CREATE_NOTES']);
$case = $ref->getMemberCase();
$caseMembers = $case->getMembers();
for ($x = 0; $x < $noteCount; $x++) {
$startTime = $gen->dateTimeBetween('06:00:00', '14:00:00');
$endTime = $gen->dateTimeBetween('12:00:00', '21:00:00');
if ($startTime > $endTime) {
$tmp = clone $endTime;
$endTime = $startTime;
$startTime = $tmp;
}
if ($ref->getServiceCode() === ReferralServiceType::VS_THBB) {
$note = new VisitNote();
$note->setReferral($ref)
->setDate($gen->dateTimeBetween($case->getAdmitDate()->format('Y-m-d'), 'now'))
->setStartTime($startTime)
->setEndTime($endTime)
->setStatus($gen->randomElement(NoteStatus::class))
->setLocation($gen->randomElement(NoteLocation::class))
->setMethod(NoteMethod::BILLABLE_SUPERVISED_VISIT)
->setParentalRole($gen->randomElement(VisitQualityLevel::class))
->setChildDevelopment($gen->randomElement(VisitQualityLevel::class))
->setAppropriateResponse($gen->randomElement(VisitQualityLevel::class))
->setChildAheadOfSelf($gen->randomElement(VisitQualityLevel::class))
->setShowsEmpathy($gen->randomElement(VisitQualityLevel::class))
->setChildFocused($gen->randomElement(VisitQualityLevel::class))
->setNarrative($gen->text(100))
->setStrengths($gen->text(100))
->setIssues($gen->text(100))
->setRecommendation($gen->text(100))
// ->setMembers(
// (
// count($caseMembers) > 0
// ?
// $gen->randomElements($caseMembers, $gen->numberBetween(1, count($caseMembers)))
// :
// null
// )
// )
;
// dd($note);
} else {
$note = new StandardNote();
$note->setReferral($ref)
->setDate($gen->dateTimeBetween('-1 year', 'now'))
->setStartTime($startTime)
->setEndTime($endTime)
->setStatus($gen->randomElement(NoteStatus::class))
->setLocation($gen->randomElement(NoteLocation::class))
->setMethod(NoteMethod::BILLABLE)
->setNote($gen->text(100))
// ->setMembers(
// (
// count($caseMembers) > 0
// ?
// $gen->randomElements($caseMembers, $gen->numberBetween(1, count($caseMembers)))
// :
// null
// )
// )
;
}
$manager->persist($note);
}
}
$manager->flush();
}
public function getDependencies(): array
{
return [
MemberCaseFixture::class,
ReferralFixture::class,
];
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace App\DataFixtures;
use App\Entity\Case\MemberCase;;
use App\Entity\Case\Referral;
use App\Enums\Case\ReferralServiceType;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
class ReferralFixture extends Fixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{
if(!$_ENV['CREATE_REFERRALS']) {
return;
}
$gen = \Faker\Factory::create();
$cases = $manager->getRepository(MemberCase::class)->findAll();
foreach ($cases as $case) {
print "Adding referrals for case {$case->getCaseNumber()}".PHP_EOL;
$refCount = $gen->numberBetween(0, $_ENV['CREATE_REFERRALS']);
for ($x = 0; $x < $refCount; $x++) {
$ref = new Referral();
$ref->setReferralId($gen->numberBetween(1000000, 9999999))
->setMemberCase($case)
->setServiceCode($gen->randomElement(ReferralServiceType::class))
->setEndDate($gen->dateTimeBetween('+1 month', '+1 year'))
->setHours($gen->numberBetween(1, 75))
;
print "Adding referral {$ref->getReferralId()}".PHP_EOL;
$manager->persist($ref);
}
}
$manager->flush();
}
public function getDependencies(): array
{
return [
MemberCaseFixture::class,
];
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace App\DataFixtures;
use App\Entity\System\ReferralSource;
use App\Enums\System\County;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use Faker\Factory;
class ReferralSourceFixture extends Fixture
{
public function load(ObjectManager $manager): void
{
if(!$_ENV['CREATE_SOURCES']) {
return;
}
$gen = Factory::create();
for ($x = 0; $x < $_ENV['CREATE_REFERRALS']; $x++) {
$src = new ReferralSource();
$name = "{$gen->firstName()} {$gen->lastName()}";
$username = strtolower(str_replace(' ', '.', $name));
$src->setName($name)
->setEmail("{$username}@dcs.in.gov")
->setCounty((string) $gen->randomElement(County::class)->name)
->setAgency('DCS')
->setPhone(str_replace(['-', '+'], '', $gen->phoneNumber()))
;
print "Adding referral source {$src->getName()}".PHP_EOL;
$manager->persist($src);
}
// $product = new Product();
// $manager->persist($product);
$manager->flush();
}
}

View File

@ -0,0 +1,65 @@
<?php
namespace App\DataFixtures;
use App\Entity\Case\MemberCase;;
use App\Entity\Staff\StaffNote;
use App\Enums\Case\ReferralServiceType;
use DateTime;
use DateTimeZone;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
use Doctrine\Persistence\ObjectManager;
class StaffNoteFixture extends Fixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager): void
{
if(!$_ENV['CREATE_STAFF_NOTES']) {
return;
}
$cases = $manager->getRepository(MemberCase::class)->findAll();
$gen = \Faker\Factory::create();
foreach ($cases as $case) {
/** @var MemberCase $case */
$note = new StaffNote();
$admitDate = new DateTime($case->getAdmitDate()?->format('Y-m-d').' '.$gen->time('H:i:s'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']));
$admitDate->add(\DateInterval::createFromDateString('7 day'));
$note->setDate($admitDate);
$note->setMemberCase($case);
$note->setServicesProvided($gen->randomElements(ReferralServiceType::class, $gen->numberBetween(1, 3)));
while ($admitDate->getTimestamp() < time()) {
$workerSignDatetime = clone $admitDate;
$workerSignDatetime->setTime($gen->time('H'), $gen->time('i'), $gen->time('s'));
$workerSignDatetime->add(\DateInterval::createFromDateString('1 day'));
$note->setWorkerSignDatetime($workerSignDatetime);
$supervisorSignDatetime = clone $admitDate;
$supervisorSignDatetime->setTime($gen->time('H'), $gen->time('i'), $gen->time('s'));
$supervisorSignDatetime->add(\DateInterval::createFromDateString('1 day'));
$note->setSupervisorSignDatetime($supervisorSignDatetime);
$note->setNote($gen->text(200));
$note->setRecommendations($gen->text(20));
$manager->persist($note);
$admitDate->add(\DateInterval::createFromDateString('14 days'));
$note = clone $note;
$note->setDate(clone $admitDate);
}
}
$manager->flush();
}
public function getDependencies(): array
{
return [
MemberCaseFixture::class,
];
}
}

View File

@ -0,0 +1,65 @@
<?php
namespace App\DataFixtures;
use App\Entity\Company\Company;
use App\Entity\System\User;
use App\Enums\Case\CaseLevel;
use App\Enums\System\RateType;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
class UserFixture extends Fixture
{
public function __construct(
private readonly UserPasswordHasherInterface $userPasswordHasher,
) {
}
public function load(ObjectManager $manager): void
{
if(!$_ENV['CREATE_USERS']) {
return;
}
$comp = $manager->getRepository(Company::class)->findOneBy(['name' => 'Counseling Partners, LLC']);
$gen = \Faker\Factory::create();
for ($x = 0; $x < $_ENV['CREATE_USERS']; $x++) {
$user = new User();
$name = $gen->firstName().' '.$gen->lastName();
$username = strtolower(str_replace(' ', '.', $name));
$cw = true;
$cm = $gen->boolean();
$t = $gen->boolean();
$su = $gen->boolean();
$roles = ['ROLE_USER', 'ROLE_CASE_WORKER'];
if ($cm) {
$roles[] = 'ROLE_CASE_MANAGER';
}
if ($t) {
$roles[] = 'ROLE_THERAPIST';
}
if ($su) {
$roles[] = 'ROLE_ADMIN';
}
$user->setName($name)
->setUsername($username)
->setEmail($username.'@counselingpartnersllc.com')
->setRoles($roles)
->setRateType($gen->randomElement(RateType::class))
->setRate($gen->numberBetween(0, 100))
->setLevel($gen->randomElement(CaseLevel::class))
->setCompany($comp)
->setPassword($this->userPasswordHasher->hashPassword($user, 'password'))
;
print "Creating user $name - $username".PHP_EOL;
$manager->persist($user);
}
$manager->flush();
}
}

View File

@ -0,0 +1,202 @@
<?php
namespace App\Entity\Case;
use App\Entity\System\Location;
use App\Repository\Case\CaseItineraryRepository;
use DateTime;
use DateInterval;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
use Symfony\UX\Map\Point;
#[ORM\Entity(repositoryClass: CaseItineraryRepository::class)]
class CaseItinerary
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private ?Uuid $id = null;
#[ORM\Column(type: Types::DATE_MUTABLE)]
private ?\DateTimeInterface $date = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $departure = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?Location $originLocation = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?Location $destLocation = null;
#[ORM\Column]
private ?bool $caseMileage = null;
#[ORM\Column]
private ?DateInterval $duration = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?MemberCase $memberCase = null;
#[ORM\Column(nullable: true)]
private ?float $distance = null;
#[ORM\Column(nullable: true)]
private ?array $gpsRoute = null;
public function getId(): ?Uuid
{
return $this->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 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;
}
public function originInfoWindow(): string
{
return <<<EOL
{$this->originLocation->getName()}<br/>
<a href='http://maps.google.com/?q={$this->originLocation->getLat()},{$this->originLocation->getLon()}'>{$this->originLocation->getFormattedAddress()}</a><br/>
{$this->departure->format("g:i a")}
EOL;
}
public function destinationInfoWindow(): string
{
/** @var DateTime $arrival */
$arrival = $this->departure;
$arrival->add($this->duration);
return <<<EOL
{$this->destLocation->getName()}<br/>
<a href='http://maps.google.com/?q={$this->destLocation->getLat()},{$this->destLocation->getLon()}'>{$this->destLocation->getFormattedAddress()}</a><br/>
{$arrival->format("g:i a")}
EOL;
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace App\Entity\Case;
use App\Entity\System\Location;
use App\Repository\Case\CaseLocationRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: CaseLocationRepository::class)]
class CaseLocation
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private ?Uuid $id = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?MemberCase $memberCase = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?Location $location = null;
public function getId(): ?int
{
return $this->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;
}
}

View File

@ -1,11 +1,11 @@
<?php
namespace App\Entity;
namespace App\Entity\Case;
use App\Enums\GenderType;
use App\Enums\RaceType;
use App\Enums\RelationshipType;
use App\Repository\MemberRepository;
use App\Enums\System\GenderType;
use App\Enums\Case\RaceType;
use App\Enums\Case\RelationshipType;
use App\Repository\Case\MemberRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
@ -23,7 +23,7 @@ class Member
#[ORM\ManyToOne(inversedBy: 'members')]
#[ORM\JoinColumn(nullable: false)]
private ?MemberCase $caseId = null;
private ?MemberCase $memberCase = null;
#[ORM\Column(length: 45)]
private ?string $lastName = null;
@ -103,19 +103,27 @@ class Member
#[ORM\Column]
private ?bool $dcsApproved = null;
private ?bool $checked = false;
public function getId(): ?Uuid
{
return $this->id;
}
public function setId(?Uuid $id): static
{
$this->id = $id;
return $this;
}
public function getCaseId(): ?MemberCase
{
return $this->caseId;
return $this->memberCase;
}
public function setCaseId(?MemberCase $caseId): static
{
$this->caseId = $caseId;
$this->memberCase = $caseId;
return $this;
}
@ -144,6 +152,11 @@ class Member
return $this;
}
public function getName(): string
{
return "{$this->firstName} {$this->lastName}";
}
public function getRelationship(): ?RelationshipType
{
return $this->relationship;
@ -446,4 +459,16 @@ class Member
return $this;
}
public function isChecked(): bool
{
return $this->checked;
}
public function setChecked(bool $checked): static
{
$this->checked = $checked;
return $this;
}
}

View File

@ -1,10 +1,14 @@
<?php
namespace App\Entity;
namespace App\Entity\Case;
use App\Enums\CaseLevel;
use App\Enums\County;
use App\Repository\MemberCaseRepository;
use App\Entity\Staff\StaffNote;
use App\Entity\System\ReferralSource;
use App\Entity\System\UserCase;
use App\Enums\Case\CaseLevel;
use App\Enums\System\County;
use App\Enums\Case\ReferralType;
use App\Repository\Case\MemberCaseRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
@ -31,7 +35,7 @@ class MemberCase
private ?string $lastName = null;
#[ORM\Column(length: 45)]
private ?string $referralType = null;
private ?ReferralType $referralType = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
@ -91,10 +95,34 @@ class MemberCase
#[ORM\OneToMany(targetEntity: Referral::class, mappedBy: 'memberCase', orphanRemoval: true)]
private Collection $referrals;
/**
* @var Collection<int, MonthlyCaseNote>
*/
#[ORM\OneToMany(targetEntity: MonthlyCaseNote::class, mappedBy: 'memberCase')]
private Collection $monthlyCaseNotes;
/**
* @var Collection<int, Member>
*/
#[ORM\OneToMany(targetEntity: Member::class, mappedBy: 'memberCase', orphanRemoval: true)]
private Collection $members;
/**
* @var Collection<int, StaffNote>
*/
#[ORM\OneToMany(targetEntity: StaffNote::class, mappedBy: 'memberCase')]
private Collection $staffNotes;
#[ORM\Column]
private ?int $rate = null;
public function __construct()
{
$this->userCases = new ArrayCollection();
$this->referrals = new ArrayCollection();
$this->monthlyCaseNotes = new ArrayCollection();
$this->members = new ArrayCollection();
$this->staffNotes = new ArrayCollection();
}
public function getId(): ?Uuid
@ -143,12 +171,12 @@ class MemberCase
return "{$this->lastName}, {$this->firstName}";
}
public function getReferralType(): ?string
public function getReferralType(): ?ReferralType
{
return $this->referralType;
}
public function setReferralType(string $referralType): static
public function setReferralType(ReferralType $referralType): static
{
$this->referralType = $referralType;
@ -394,4 +422,112 @@ class MemberCase
return $this;
}
/**
* @return Collection<int, MonthlyCaseNote>
*/
public function getMonthlyCaseNotes(): Collection
{
return $this->monthlyCaseNotes;
}
public function addMonthlyCaseNote(MonthlyCaseNote $monthlyCaseNote): static
{
if (!$this->monthlyCaseNotes->contains($monthlyCaseNote)) {
$this->monthlyCaseNotes->add($monthlyCaseNote);
$monthlyCaseNote->setMemberCase($this);
}
return $this;
}
public function removeMonthlyCaseNote(MonthlyCaseNote $monthlyCaseNote): static
{
if ($this->monthlyCaseNotes->removeElement($monthlyCaseNote)) {
// set the owning side to null (unless already changed)
if ($monthlyCaseNote->getMemberCase() === $this) {
$monthlyCaseNote->setMemberCase(null);
}
}
return $this;
}
/**
* @return Collection<int, Member>
*/
public function getMembers(): Collection
{
return $this->members;
}
public function addMember(Member $member): static
{
if (!$this->members->contains($member)) {
$this->members->add($member);
$member->setCaseId($this);
}
return $this;
}
public function removeMember(Member $member): static
{
if ($this->members->removeElement($member)) {
// set the owning side to null (unless already changed)
if ($member->getCaseId() === $this) {
$member->setCaseId(null);
}
}
return $this;
}
/**
* @return Collection<int, StaffNote>
*/
public function getStaffNotes(): Collection
{
return $this->staffNotes;
}
public function addStaffNote(StaffNote $staffNote): static
{
if (!$this->staffNotes->contains($staffNote)) {
$this->staffNotes->add($staffNote);
$staffNote->setMemberCase($this);
}
return $this;
}
public function removeStaffNote(StaffNote $staffNote): static
{
if ($this->staffNotes->removeElement($staffNote)) {
// set the owning side to null (unless already changed)
if ($staffNote->getMemberCase() === $this) {
$staffNote->setMemberCase(null);
}
}
return $this;
}
public function emptyStaffNotes(): static
{
$this->staffNotes->clear();
return $this;
}
public function getRate(): ?int
{
return $this->rate;
}
public function setRate(int $rate): static
{
$this->rate = $rate;
return $this;
}
}

View File

@ -0,0 +1,149 @@
<?php
namespace App\Entity\Case;
use App\Entity\Company\CompanyDocument;
use App\Entity\System\User;
use App\Repository\Case\MemberDocumentRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: MemberDocumentRepository::class)]
class MemberDocument
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private ?Uuid $id = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?Member $client = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?User $caseWorker = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $clientSigned = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $workerSigned = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?CompanyDocument $document = null;
#[ORM\Column(nullable: true)]
private ?array $clientSignature = null;
#[ORM\Column(nullable: true)]
private ?array $workerSignature = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $docData = null;
public function getId(): ?Uuid
{
return $this->id;
}
public function getClient(): ?Member
{
return $this->client;
}
public function setClient(?Member $client): static
{
$this->client = $client;
return $this;
}
public function getCaseWorker(): ?User
{
return $this->caseWorker;
}
public function setCaseWorker(?User $caseWorker): static
{
$this->caseWorker = $caseWorker;
return $this;
}
public function getClientSigned(): ?\DateTimeInterface
{
return $this->clientSigned;
}
public function setClientSigned(?\DateTimeInterface $clientSigned): static
{
$this->clientSigned = $clientSigned;
return $this;
}
public function getWorkerSigned(): ?\DateTimeInterface
{
return $this->workerSigned;
}
public function setWorkerSigned(?\DateTimeInterface $workerSigned): static
{
$this->workerSigned = $workerSigned;
return $this;
}
public function getDocument(): ?CompanyDocument
{
return $this->document;
}
public function setDocument(?CompanyDocument $document): static
{
$this->document = $document;
return $this;
}
public function getClientSignature(): ?array
{
return $this->clientSignature;
}
public function setClientSignature(?array $clientSignature): static
{
$this->clientSignature = $clientSignature;
return $this;
}
public function getWorkerSignature(): ?array
{
return $this->workerSignature;
}
public function setWorkerSignature(?array $workerSignature): static
{
$this->workerSignature = $workerSignature;
return $this;
}
public function getDocData(): ?string
{
return $this->docData;
}
public function setDocData(?string $docData): static
{
$this->docData = $docData;
return $this;
}
}

View File

@ -0,0 +1,115 @@
<?php
namespace App\Entity\Case;
use App\Repository\Case\MonthlyCaseNoteRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: MonthlyCaseNoteRepository::class)]
class MonthlyCaseNote
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private ?Uuid $id = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $reason = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $familyStrength = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $recAndProgress = null;
#[ORM\ManyToOne(inversedBy: 'monthlyCaseNotes')]
#[ORM\JoinColumn(nullable: false)]
private ?MemberCase $memberCase = null;
#[ORM\Column(type: Types::DATE_MUTABLE)]
private ?\DateTimeInterface $date = null;
#[ORM\Column(type: Types::DATE_MUTABLE)]
private ?\DateTimeInterface $nextVisit = null;
public function getId(): ?Uuid
{
return $this->id;
}
public function getReason(): ?string
{
return $this->reason;
}
public function setReason(?string $reason): static
{
$this->reason = $reason;
return $this;
}
public function getFamilyStrength(): ?string
{
return $this->familyStrength;
}
public function setFamilyStrength(?string $familyStrength): static
{
$this->familyStrength = $familyStrength;
return $this;
}
public function getRecAndProgress(): ?string
{
return $this->recAndProgress;
}
public function setRecAndProgress(?string $recAndProgress): static
{
$this->recAndProgress = $recAndProgress;
return $this;
}
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 getNextVisit(): ?\DateTimeInterface
{
return $this->nextVisit;
}
public function setNextVisit(\DateTimeInterface $nextVisit): static
{
$this->nextVisit = $nextVisit;
return $this;
}
}

193
src/Entity/Case/Note.php Normal file
View File

@ -0,0 +1,193 @@
<?php
namespace App\Entity\Case;
use App\Enums\Case\NoteLocation;
use App\Enums\Case\NoteMethod;
use App\Enums\Case\NoteStatus;
use App\Repository\Case\NoteRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\MappedSuperclass;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[MappedSuperclass(NoteRepository::class)]
class Note
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private ?Uuid $id = null;
#[ORM\Column(type: Types::DATE_MUTABLE)]
private ?\DateTimeInterface $date = null;
#[ORM\ManyToOne(inversedBy: 'notes')]
#[ORM\JoinColumn(nullable: false)]
private ?Referral $referral = null;
#[ORM\Column(type: Types::TIME_MUTABLE)]
private ?\DateTimeInterface $startTime = null;
#[ORM\Column(type: Types::TIME_MUTABLE)]
private ?\DateTimeInterface $endTime = null;
#[ORM\Column(enumType: NoteStatus::class)]
private ?NoteStatus $status = null;
#[ORM\Column(enumType: NoteLocation::class)]
private ?NoteLocation $location = null;
#[ORM\Column(enumType: NoteMethod::class)]
private ?NoteMethod $method = null;
private ?array $members = null;
public function __construct()
{
$this->members = [];
}
public function getId(): ?UUid
{
return $this->id;
}
public function getDate(): ?\DateTimeInterface
{
return $this->date;
}
public function setDate(\DateTimeInterface $date): static
{
$this->date = $date;
return $this;
}
public function getReferral(): ?Referral
{
return $this->referral;
}
public function setReferral(?Referral $referral): static
{
$this->referral = $referral;
return $this;
}
public function getStartTime(): ?\DateTimeInterface
{
return $this->startTime;
}
public function setStartTime(\DateTimeInterface $startTime): static
{
$this->startTime = $startTime;
return $this;
}
public function getEndTime(): ?\DateTimeInterface
{
return $this->endTime;
}
public function setEndTime(\DateTimeInterface $endTime): static
{
$this->endTime = $endTime;
return $this;
}
public function getStatus(): ?NoteStatus
{
return $this->status;
}
public function setStatus(NoteStatus $status): static
{
$this->status = $status;
return $this;
}
public function getLocation(): ?NoteLocation
{
return $this->location;
}
public function setLocation(NoteLocation $location): static
{
$this->location = $location;
return $this;
}
public function getMethod(): ?NoteMethod
{
return $this->method;
}
public function setMethod(NoteMethod $method): static
{
$this->method = $method;
return $this;
}
public function getMembers(): ?array
{
return $this->members;
}
public function setMembers(?array $members): static
{
$this->members = $members;
return $this;
}
public function addMember(Member $member): static
{
$this->members[] = $member;
return $this;
}
/**
* Method to calculate the number of minutes used for a visit rounded to the nearest 15 min increment
*
* @param int $precision
* The number of minutes to round the time to defaulted to 15
*
* @return int
* The number of minutes calculated
*/
public function calcTimeUsed(int $precision = 15): int
{
// get the number of seconds between the two times
$timestamp = $this->endTime->getTimestamp() - $this->startTime->getTimestamp();
// find out how many increments of precision there are between these two increments
$increments = ($timestamp / 60) / $precision;
// if the number of increments is a float that means there is a difference
if (is_float($increments)) {
// calculate the modulo
$mod = ($timestamp / 60) % $precision;
// if the modulo is higher than half the precision increment increase the increments by 1
if ($mod >= ($precision / 2)) {
$increments++;
}
// convert the increments to an integer
$increments = (int) $increments;
}
// return the number of increments times the precision to the partials
return $increments * $precision;
}
}

View File

@ -1,10 +1,10 @@
<?php
namespace App\Entity;
namespace App\Entity\Case;
use App\Enums\DischargeReason;
use App\Enums\ReferralServiceType;
use App\Repository\ReferralRepository;
use App\Enums\Case\DischargeReason;
use App\Enums\Case\ReferralServiceType;
use App\Repository\Case\ReferralRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
@ -41,6 +41,19 @@ class Referral
#[ORM\Column(type: Types::DATE_MUTABLE, nullable: true)]
private ?\DateTimeInterface $dischargeDate = null;
/**
* @var float $hoursUsed
*/
private float $hoursUsed = 0.0;
/**
* Constructor
*/
public function __construct()
{
$this->hoursUsed = 0.0;
}
public function getId(): ?Uuid
{
return $this->id;
@ -129,4 +142,14 @@ class Referral
return $this;
}
public function getHoursRemaining(): float
{
return $this->hours - $this->hoursUsed;
}
public function getHoursUsed(): float
{
return $this->hoursUsed;
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Entity\Case;
use App\Enums\Case\ReferralServiceType;
use App\Repository\Case\StandardNoteRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use JsonSerializable;
#[ORM\Entity(repositoryClass: StandardNoteRepository::class)]
class StandardNote extends Note implements JsonSerializable
{
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $note = null;
public function getNote(): ?string
{
return $this->note;
}
public function setNote(?string $note): static
{
$this->note = $note;
return $this;
}
public function jsonSerialize(): array
{
$members = [];
foreach ($this->getMembers() as $member) {
/** @var StandardNoteMember $member */
$members[] = $member->getPerson()->getName();
}
return [
'id' => $this->getId()->toString(),
'date' => $this->getDate()->format('M j, Y'),
'startTime' => $this->getStartTime()->format('g:i a'),
'endTime' => $this->getEndTime()->format('g:i a'),
'serviceCode' => $this->getReferral()->getServiceCode()->value,
'noteType' => ($this->getReferral()->getServiceCode() == ReferralServiceType::VS_THBB ? 'visit' : 'standard'),
'status' => $this->getStatus()->value,
'location' => $this->getLocation()->value,
'method' => ucwords(str_replace('_', ' ', strtolower($this->getMethod()->name))),
'members' => implode(', ', $members),
'duration' => $this->calcTimeUsed(),
];
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace App\Entity\Case;
use App\Repository\Case\StandardNoteMemberRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: StandardNoteMemberRepository::class)]
class StandardNoteMember
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private ?Uuid $id = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?StandardNote $note = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?Member $person = null;
public function getId(): ?Uuid
{
return $this->id;
}
public function getStandardNote(): ?StandardNote
{
return $this->note;
}
public function setStandardNote(?StandardNote $note): static
{
$this->note = $note;
return $this;
}
public function getPerson(): ?Member
{
return $this->person;
}
public function setPerson(?Member $person): static
{
$this->person = $person;
return $this;
}
}

View File

@ -0,0 +1,196 @@
<?php
namespace App\Entity\Case;
use App\Enums\Case\ReferralServiceType;
use App\Enums\Case\VisitQualityLevel;
use App\Repository\Case\VisitNoteRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use JsonSerializable;
#[ORM\Entity(repositoryClass: VisitNoteRepository::class)]
class VisitNote extends Note implements JsonSerializable
{
#[ORM\Column(type: Types::TEXT)]
private ?string $narrative = null;
#[ORM\Column(type: Types::TEXT)]
private ?string $strengths = null;
#[ORM\Column(type: Types::TEXT)]
private ?string $issues = null;
#[ORM\Column(type: Types::TEXT)]
private ?string $recommendation = null;
#[ORM\Column(enumType: VisitQualityLevel::class)]
private ?VisitQualityLevel $parentalRole = null;
#[ORM\Column(enumType: VisitQualityLevel::class)]
private ?VisitQualityLevel $childDevelopment = null;
#[ORM\Column(enumType: VisitQualityLevel::class)]
private ?VisitQualityLevel $appropriateResponse = null;
#[ORM\Column(enumType: VisitQualityLevel::class)]
private ?VisitQualityLevel $childAheadOfSelf = null;
#[ORM\Column(enumType: VisitQualityLevel::class)]
private ?VisitQualityLevel $showsEmpathy = null;
#[ORM\Column(enumType: VisitQualityLevel::class)]
private ?VisitQualityLevel $childFocused = null;
public function getNarrative(): ?string
{
return $this->narrative;
}
public function setNarrative(string $narrative): static
{
$this->narrative = $narrative;
return $this;
}
public function getStrengths(): ?string
{
return $this->strengths;
}
public function setStrengths(string $strengths): static
{
$this->strengths = $strengths;
return $this;
}
public function getIssues(): ?string
{
return $this->issues;
}
public function setIssues(string $issues): static
{
$this->issues = $issues;
return $this;
}
public function getRecommendation(): ?string
{
return $this->recommendation;
}
public function setRecommendation(string $recommendation): static
{
$this->recommendation = $recommendation;
return $this;
}
public function getParentalRole(): ?VisitQualityLevel
{
return $this->parentalRole;
}
public function setParentalRole(VisitQualityLevel $parentalRole): static
{
$this->parentalRole = $parentalRole;
return $this;
}
public function getChildDevelopment(): ?VisitQualityLevel
{
return $this->childDevelopment;
}
public function setChildDevelopment(VisitQualityLevel $childDevelopment): static
{
$this->childDevelopment = $childDevelopment;
return $this;
}
public function getAppropriateResponse(): ?VisitQualityLevel
{
return $this->appropriateResponse;
}
public function setAppropriateResponse(VisitQualityLevel $appropriateResponse): static
{
$this->appropriateResponse = $appropriateResponse;
return $this;
}
public function getChildAheadOfSelf(): ?VisitQualityLevel
{
return $this->childAheadOfSelf;
}
public function setChildAheadOfSelf(VisitQualityLevel $childAheadOfSelf): static
{
$this->childAheadOfSelf = $childAheadOfSelf;
return $this;
}
public function getShowsEmpathy(): ?VisitQualityLevel
{
return $this->showsEmpathy;
}
public function setShowsEmpathy(VisitQualityLevel $showsEmpathy): static
{
$this->showsEmpathy = $showsEmpathy;
return $this;
}
public function getChildFocused(): ?VisitQualityLevel
{
return $this->childFocused;
}
public function setChildFocused(VisitQualityLevel $childFocused): static
{
$this->childFocused = $childFocused;
return $this;
}
public function jsonSerialize(): array
{
$members = [];
foreach ($this->getMembers() as $member) {
/** @var VisitNoteMembers $member */
$members[] = $member->getPerson()->getName();
}
return [
'id' => $this->getId()->toString(),
'date' => $this->getDate()->format('M j, Y'),
'startTime' => $this->getStartTime()->format('g:i a'),
'endTime' => $this->getEndTime()->format('g:i a'),
'serviceCode' => $this->getReferral()->getServiceCode()->value,
'noteType' => ($this->getReferral()->getServiceCode() == ReferralServiceType::VS_THBB ? 'visit' : 'standard'),
'status' => $this->getStatus()->value,
'location' => $this->getLocation()->value,
'method' => ucwords(str_replace('_', ' ', strtolower($this->getMethod()->name))),
'narrative' => $this->getNarrative(),
'strengths' => $this->getStrengths(),
'issues' => $this->getIssues(),
'recommendation' => $this->getRecommendation(),
'parentalRole' => $this->getParentalRole(),
'childDevelopment' => $this->getChildDevelopment(),
'appropriateResponse' => $this->getAppropriateResponse(),
'childAheadOfSelf' => $this->getChildAheadOfSelf(),
'showsEmpathy' => $this->getShowsEmpathy(),
'childFocused' => $this->getChildFocused(),
'members' => implode(', ', $members),
'duration' => $this->calcTimeUsed(),
];
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace App\Entity\Case;
use App\Repository\Case\VisitNoteMembersRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: VisitNoteMembersRepository::class)]
class VisitNoteMembers
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private ?Uuid $id = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?VisitNote $note = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?Member $person = null;
public function getId(): ?int
{
return $this->id;
}
public function getVisitNote(): ?VisitNote
{
return $this->note;
}
public function setVisitNote(?VisitNote $note): static
{
$this->note = $note;
return $this;
}
public function getPerson(): ?Member
{
return $this->person;
}
public function setPerson(?Member $person): static
{
$this->person = $person;
return $this;
}
}

View File

@ -1,13 +1,17 @@
<?php
namespace App\Entity;
namespace App\Entity\Company;
use App\Repository\CompanyRepository;
use App\Entity\System\User;
use App\Repository\Company\CompanyRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
use Vich\UploaderBundle\Entity\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
#[ORM\Entity(repositoryClass: CompanyRepository::class)]
class Company
@ -42,6 +46,15 @@ class Company
#[ORM\Column(length: 255, nullable: true)]
private ?string $url = null;
#[Vich\UploadableField(mapping: 'profile_image', fileNameProperty: 'imageName', size: 'size', mimeType: 'mimeType', originalName: 'originalName', dimensions: 'dimensions')]
private ?File $imageFile = null;
#[ORM\Column(type: Types::STRING, length: 255, nullable: true)]
private ?string $companyLogo = null;
#[ORM\Column(length: 64)]
private ?string $vendorId = null;
/**
* @var Collection<int, User>
*/
@ -200,6 +213,42 @@ class Company
return $this;
}
public function getImageFile(): ?File
{
return $this->imageFile;
}
public function setImageFile(?File $imageFile): static
{
$this->imageFile = $imageFile;
return $this;
}
public function getCompanyLogo(): ?string
{
return $this->companyLogo;
}
public function setCompanyLogo(?string $companyLogo): static
{
$this->companyLogo = $companyLogo;
return $this;
}
public function getVendorId(): ?string
{
return $this->vendorId;
}
public function setVendorId(string $vendorId): static
{
$this->vendorId = $vendorId;
return $this;
}
public function __toString(): string
{
$url = ($this->url ? "<br/><a href='$this->url' target='_blank'>$this->url</a>" : '');

View File

@ -0,0 +1,139 @@
<?php
namespace App\Entity\Company;
use App\Enums\Company\DocumentExtras;
use App\Repository\Company\CompanyDocumentRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: CompanyDocumentRepository::class)]
class CompanyDocument
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private ?Uuid $id = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?Company $company = null;
#[ORM\Column(length: 255)]
private ?string $title = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $text = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
private ?\DateTimeInterface $updated = null;
#[ORM\Column(type: Types::JSON, enumType: DocumentExtras::class, nullable: true)]
private array $extras = [];
private bool $selected = false;
public function getId(): ?Uuid
{
return $this->id;
}
public function getCompany(): ?Company
{
return $this->company;
}
public function setCompany(?Company $company): static
{
$this->company = $company;
return $this;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): static
{
$this->title = $title;
return $this;
}
public function getText(): ?string
{
return $this->text;
}
public function setText(?string $text): static
{
$this->text = $text;
return $this;
}
public function getUpdated(): ?\DateTimeInterface
{
return $this->updated;
}
public function setUpdated(\DateTimeInterface $updated): static
{
$this->updated = $updated;
return $this;
}
public function isSelected(): bool
{
return $this->selected;
}
public function setSelected(): static
{
$this->selected = true;
return $this;
}
public function getExtras(): array
{
return $this->extras;
}
public function setExtras(array $extras): static
{
$this->extras = $extras;
return $this;
}
public function inExtras(DocumentExtras $field): bool
{
return in_array($field, $this->extras);
}
public function renderHtml(): string
{
$text = $this->text;
if ($this->inExtras(DocumentExtras::EMAIL)) {
$text = str_replace('{{ email }}', "<input type='email' name='email' id='email' value='{{ doc.client.email }}'/>", $text);
$text = str_replace('{{ checkbox|email }}', "<input type='checkbox' name='emailClient' id='emailClient' value='1'/>", $text);
}
if ($this->inExtras(DocumentExtras::PHONE)) {
$text = str_replace('{{ phone }}', "<input type='tel' name='phone' id='phone' value='{{ doc.client.phone }}'/>", $text);
$text = str_replace('{{ checkbox|phone }}', "<input type='checkbox' name='callClient' id='callClient' value='1'/>", $text);
$text = str_replace('{{ checkbox|text }}', "<input type='checkbox' name='textClient' id='textClient' value='1'/>", $text);
}
return <<<HTML
$text
HTML;
}
}

View File

@ -0,0 +1,702 @@
<?php
namespace App\Entity\Resources;
use App\Entity\System\Location;
use App\Enums\System\County;
use App\Enums\Case\ResourceType;
use App\Enums\System\State;
use App\Libs\Libs;
use App\Repository\Resources\CommunityResourceRepository;
use DateTime;
use DateTimeZone;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: CommunityResourceRepository::class)]
class CommunityResource
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private ?Uuid $id = null;
#[ORM\Column(length: 255)]
private ?string $name = null;
#[ORM\Column(length: 255)]
private ?string $address = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $address2 = null;
#[ORM\Column(length: 255)]
private ?string $city = null;
#[ORM\Column(enumType: State::class)]
private ?State $state = null;
#[ORM\Column]
private ?int $zip = null;
#[ORM\Column(enumType: County::class)]
private ?County $county = null;
#[ORM\Column(length: 15, nullable: true)]
private ?string $phone = null;
#[ORM\Column(length: 64, nullable: true)]
private ?string $email = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $url = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $monOpen = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $monClose = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $tueOpen = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $tueClose = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $wedOpen = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $wedClose = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $thuOpen = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $thuClose = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $friOpen = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $friClose = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $satOpen = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $satClose = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $sunOpen = null;
#[ORM\Column(type: Types::TIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $sunClose = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $notes = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $servicesAvailable = null;
#[ORM\Column(type: Types::JSON, enumType: ResourceType::class)]
private array $type = [];
#[ORM\Column(nullable: true)]
private ?float $lat = null;
#[ORM\Column(nullable: true)]
private ?float $lon = null;
public function __construct(
private DateTime $today = new DateTime('now', new DateTimeZone('America/Indiana/Indianapolis'))
) {
}
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 : '') . '<br/>' .
$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 "<a href='$this->url' target='_blank'><i class='fa-brands fa-facebook'></i></a>";
} else {
return "<a href='$this->url' target='_blank'><i class='fa-solid fa-globe'></i></a>";
}
return null;
}
public function getContactCard(): ?string
{
$formattedPhone = ($this->phone ? Libs::formatPhone($this->phone) : '');
return ($this->email ? "<a href='mailto:$this->email'>$this->email</a><br/>" : '') .
($this->phone ? "<a href='tel:$this->phone'>$formattedPhone</a>" : '');
}
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'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']));
if ($closeAt <= new DateTime('now', new DateTimeZone($_ENV['COMPANY_TIMEZONE']))) {
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'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']));
if ($closeAt <= new DateTime('now', new DateTimeZone($_ENV['COMPANY_TIMEZONE']))) {
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'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']));
if ($closeAt <= new DateTime('now', new DateTimeZone($_ENV['COMPANY_TIMEZONE']))) {
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'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']));
if ($closeAt <= new DateTime('now', new DateTimeZone($_ENV['COMPANY_TIMEZONE']))) {
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'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']));
if ($closeAt <= new DateTime('now', new DateTimeZone($_ENV['COMPANY_TIMEZONE']))) {
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'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']));
if ($closeAt <= new DateTime('now', new DateTimeZone($_ENV['COMPANY_TIMEZONE']))) {
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'), new DateTimeZone($_ENV['COMPANY_TIMEZONE']));
if ($closeAt <= new DateTime('now', new DateTimeZone($_ENV['COMPANY_TIMEZONE']))) {
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($_ENV['COMPANY_TIMEZONE']));
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 <<<HTML
<p>Sun: {$sun}</p>
<p>Mon: {$mon}</p>
<p>Tue: {$tue}</p>
<p>Wed: {$wed}</p>
<p>Thu: {$thu}</p>
<p>Fri: {$fri}</p>
<p>Sat: {$sat}</p>
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;
}
/**
* @return ResourceType[]
*/
public function getType(): array
{
return $this->type;
}
public function setType(array $type): static
{
$this->type = $type;
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;
}
public function _toInfoWindow(): string
{
return <<<EOL
{$this->name}<br/>
<a href='http://maps.google.com/?q={$this->lat},{$this->lon}'>{$this->address}<br/>
{$this->city}, {$this->state->value} {$this->zip}</a><br/>
{$this->servicesAvailable}<br/>
{$this->getContactCard()}
EOL;
}
public function toLocation(): Location
{
$loc = new Location();
$loc->setName($this->name)
->setAddress($this->address)
->setCity($this->city)
->setState($this->state)
->setZip($this->zip)
->setLat($this->lat)
->setLon($this->lon)
;
return $loc;
}
}

View File

@ -0,0 +1,132 @@
<?php
namespace App\Entity\Staff;
use App\Entity\Case\MemberCase;
use App\Enums\Case\ReferralServiceType;
use App\Repository\Staff\StaffNoteRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: StaffNoteRepository::class)]
class StaffNote
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(type: Types::DATE_MUTABLE)]
private ?\DateTimeInterface $date = null;
#[ORM\ManyToOne(inversedBy: 'staffNotes')]
#[ORM\JoinColumn(nullable: false)]
private ?MemberCase $memberCase = null;
#[ORM\Column(type: Types::SIMPLE_ARRAY, enumType: ReferralServiceType::class)]
private array $servicesProvided = [];
#[ORM\Column(type: Types::TEXT)]
private ?string $note = null;
#[ORM\Column(length: 500, nullable: true)]
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
{
return $this->id;
}
public function getDate(): ?\DateTimeInterface
{
return $this->date;
}
public function setDate(\DateTimeInterface $date): static
{
$this->date = $date;
return $this;
}
public function getMemberCase(): ?MemberCase
{
return $this->memberCase;
}
public function setMemberCase(?MemberCase $memberCase): static
{
$this->memberCase = $memberCase;
return $this;
}
/**
* @return ReferralServiceType[]
*/
public function getServicesProvided(): array
{
return $this->servicesProvided;
}
public function setServicesProvided(array $servicesProvided): static
{
$this->servicesProvided = $servicesProvided;
return $this;
}
public function getNote(): ?string
{
return $this->note;
}
public function setNote(string $note): static
{
$this->note = $note;
return $this;
}
public function getRecommendations(): ?string
{
return $this->recommendations;
}
public function setRecommendations(string $recommendations): static
{
$this->recommendations = $recommendations;
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

@ -1,8 +1,9 @@
<?php
namespace App\Entity;
namespace App\Entity\Staff;
use App\Repository\SupervisionRepository;
use App\Entity\System\User;
use App\Repository\Staff\SupervisionRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;

View File

@ -0,0 +1,140 @@
<?php
namespace App\Entity\System;
use App\Enums\System\State;
use App\Repository\System\LocationRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: LocationRepository::class)]
class Location
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private ?Uuid $id = null;
#[ORM\Column(length: 45)]
private ?string $name = null;
#[ORM\Column(length: 255)]
private ?string $address = null;
#[ORM\Column(length: 100, nullable: true)]
private ?string $city = null;
#[ORM\Column(length: 10, nullable: true)]
private ?State $state = null;
#[ORM\Column(nullable: true)]
private ?int $zip = null;
#[ORM\Column(type: Types::DECIMAL, precision: 10, scale: 6, nullable: true)]
private ?string $lat = null;
#[ORM\Column(type: Types::DECIMAL, precision: 10, scale: 6, nullable: true)]
private ?string $lon = null;
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 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}<br/>{$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}";
}
}

View File

@ -0,0 +1,159 @@
<?php
namespace App\Entity\System;
use App\Enums\System\MessageType;
use App\Repository\System\MessagesRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: MessagesRepository::class)]
class Messages
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private ?Uuid $id = null;
#[ORM\Column]
private ?\DateTimeImmutable $sent = null;
#[ORM\Column(nullable: true)]
private ?\DateTimeImmutable $received = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?User $recipient = null;
#[ORM\Column(enumType: MessageType::class)]
private ?MessageType $type = null;
#[ORM\Column(type: Types::TEXT)]
private ?string $message = null;
#[ORM\Column(length: 255)]
private ?string $title = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?User $sender = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $link = null;
public function getId(): ?Uuid
{
return $this->id;
}
public function getSent(): ?\DateTimeImmutable
{
return $this->sent;
}
public function setSent(\DateTimeImmutable $sent): static
{
$this->sent = $sent;
return $this;
}
public function getReceived(): ?\DateTimeImmutable
{
return $this->received;
}
public function setReceived(?\DateTimeImmutable $received): static
{
$this->received = $received;
return $this;
}
public function getRecipient(): ?User
{
return $this->recipient;
}
public function setRecipient(?User $recipient): static
{
$this->recipient = $recipient;
return $this;
}
public function getType(): ?MessageType
{
return $this->type;
}
public function setType(MessageType $type): static
{
$this->type = $type;
return $this;
}
public function getMessage(): ?string
{
return $this->message;
}
public function setMessage(string $message): static
{
$this->message = $message;
return $this;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): static
{
$this->title = $title;
return $this;
}
public function getSender(): ?User
{
return $this->sender;
}
public function setSender(?User $sender): static
{
$this->sender = $sender;
return $this;
}
public function toArray(): array
{
return [
'id' => $this->id->toHex(),
'title' => $this->title,
'sender' => $this->sender->getName(),
'type' => $this->type->name,
'date' => $this->sent,
'message' => $this->message
];
}
public function getLink(): ?string
{
return $this->link;
}
public function setLink(?string $link): static
{
$this->link = $link;
return $this;
}
}

View File

@ -1,8 +1,8 @@
<?php
namespace App\Entity;
namespace App\Entity\System;
use App\Repository\ReferralSourceRepository;
use App\Repository\System\ReferralSourceRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;

View File

@ -0,0 +1,86 @@
<?php
namespace App\Entity\System;
use App\Enums\System\UserSubscriptions;
use App\Repository\System\SubscriptionRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;
#[ORM\Entity(repositoryClass: SubscriptionRepository::class)]
class Subscription
{
#[ORM\Id]
#[ORM\Column(type: UuidType::NAME, unique: true)]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
private ?Uuid $id = null;
#[ORM\ManyToOne(inversedBy: 'subscriptions')]
#[ORM\JoinColumn(nullable: false)]
private ?User $user = null;
#[ORM\Column]
private ?bool $active = null;
#[ORM\Column(type: Types::DATE_MUTABLE)]
private ?\DateTimeInterface $expiration = null;
#[ORM\Column(enumType: UserSubscriptions::class)]
private ?UserSubscriptions $level = null;
public function getId(): ?Uuid
{
return $this->id;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): static
{
$this->user = $user;
return $this;
}
public function isActive(): ?bool
{
return $this->active;
}
public function setActive(bool $active): static
{
$this->active = $active;
return $this;
}
public function getExpiration(): ?\DateTimeInterface
{
return $this->expiration;
}
public function setExpiration(\DateTimeInterface $expiration): static
{
$this->expiration = $expiration;
return $this;
}
public function getLevel(): ?UserSubscriptions
{
return $this->level;
}
public function setLevel(UserSubscriptions $level): static
{
$this->level = $level;
return $this;
}
}

View File

@ -1,10 +1,11 @@
<?php
namespace App\Entity;
namespace App\Entity\System;
use App\Repository\UserRepository;
use App\Enums\RateType;
use App\Enums\CaseLevel;
use App\Entity\Company\Company;
use App\Repository\System\UserRepository;
use App\Enums\System\RateType;
use App\Enums\Case\CaseLevel;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
@ -14,10 +15,13 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Uid\Uuid;
use Vich\UploaderBundle\Entity\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_USERNAME', fields: ['username'])]
#[UniqueEntity(fields: ['username'], message: 'There is already an account with this username')]
#[Vich\Uploadable]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
@ -44,7 +48,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\Column(length: 45)]
private ?string $name = null;
#[ORM\Column(length: 45)]
#[ORM\Column(length: 64)]
private ?string $email = null;
#[ORM\Column(enumType: RateType::class)]
@ -60,29 +64,48 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\Column(enumType: CaseLevel::class)]
private ?CaseLevel $level = null;
private ?User $supervisor = null;
#[ORM\Column]
private ?bool $caseWorker = null;
#[ORM\Column]
private ?bool $caseManager = null;
#[ORM\Column]
private ?bool $therapist = null;
#[ORM\Column]
private ?bool $su = null;
/**
* @var Collection<int, UserCase>
*/
#[ORM\OneToMany(targetEntity: UserCase::class, mappedBy: 'user')]
private Collection $userCases;
#[Vich\UploadableField(mapping: 'profile_image', fileNameProperty: 'imageName', size: 'size', mimeType: 'mimeType', originalName: 'originalName', dimensions: 'dimensions')]
private ?File $imageFile = null;
#[ORM\Column(type: Types::STRING, length: 255, nullable: true)]
private ?string $imageName = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
private ?\DateTimeInterface $passwordChanged = null;
#[ORM\Column(length: 15, nullable: true)]
private ?string $personalPhone = null;
#[ORM\Column(length: 15)]
private ?string $workPhone = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $signature = null;
#[ORM\Column]
private ?bool $active = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $lastLogin = null;
private ?User $supervisor = null;
/**
* @var Collection<int, Subscription>
*/
#[ORM\OneToMany(targetEntity: Subscription::class, mappedBy: 'user', orphanRemoval: true)]
private Collection $subscriptions;
public function __construct()
{
$this->userCases = new ArrayCollection();
$this->subscriptions = new ArrayCollection();
}
public function getId(): ?Uuid
@ -240,36 +263,6 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this;
}
public function retrieveUnreadNotifications(): array
{
return [
[
'id' => 1,
'title' => 'Welcome',
'from' => 'Admin',
'type' => 'info',
'message' => 'Welcome to the dashboard.',
'timestamp' => new \DateTime('2024-11-12 10:00:00'),
],
[
'id' => 2,
'title' => 'New Case',
'from' => 'Admin',
'type' => 'info',
'message' => 'You have a new case.',
'timestamp' => new \DateTime('2024-11-13 10:19:56'),
],
[
'id' => 3,
'title' => 'New Message',
'from' => 'Admin',
'type' => 'warning',
'message' => 'You have a new message.',
'timestamp' => new \DateTime('2024-11-16 11:13:25'),
],
];
}
public function getSupervisor(): ?User
{
return $this->supervisor;
@ -284,71 +277,206 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
public function isCaseWorker(): ?bool
{
return $this->caseWorker;
}
public function setCaseWorker(bool $caseWorker): static
{
$this->caseWorker = $caseWorker;
return $this;
return in_array('ROLE_CASE_WORKER', $this->roles);
}
public function isCaseManager(): ?bool
{
return $this->caseManager;
}
public function setCaseManager(bool $caseManager): static
{
$this->caseManager = $caseManager;
return $this;
return in_array('ROLE_CASE_MANAGER', $this->roles);
}
public function isTherapist(): ?bool
{
return $this->therapist;
return in_array('ROLE_THERAPIST', $this->roles);
}
public function setTherapist(bool $therapist): static
public function isAdmin(): ?bool
{
$this->therapist = $therapist;
return $this;
}
public function isSu(): ?bool
{
return $this->su;
}
public function setSu(bool $su): static
{
$this->su = $su;
return $this;
return in_array('ROLE_ADMIN', $this->roles);
}
public function getJobs(): array
{
$jobs = [];
if ($this->caseWorker) {
if (in_array('ROLE_CASE_WORKER', $this->roles)) {
$jobs[] = 'Case Worker';
}
if ($this->caseManager) {
if (in_array('ROLE_CASE_MANAGER', $this->roles)) {
$jobs[] = 'Case Manager';
}
if ($this->therapist) {
if (in_array('ROLE_THERAPIST', $this->roles)) {
$jobs[] = 'Therapist';
}
if ($this->su) {
if (in_array('ROLE_ADMIN', $this->roles)) {
$jobs[] = 'Admin';
}
return $jobs;
}
public function getImageFile(): ?File
{
return $this->imageFile;
}
public function setImageFile(?File $imageFile): static
{
$this->imageFile = $imageFile;
return $this;
}
public function getImageName(): ?string
{
return $this->imageName;
}
public function setImageName(?string $imageName): static
{
$this->imageName = $imageName;
return $this;
}
public function getPasswordChanged(): ?\DateTimeInterface
{
return $this->passwordChanged;
}
public function setPasswordChanged(\DateTimeInterface $passwordChanged): static
{
$this->passwordChanged = $passwordChanged;
return $this;
}
public function getPersonalPhone(): ?string
{
return $this->personalPhone;
}
public function setPersonalPhone(?string $personalPhone): static
{
$this->personalPhone = $personalPhone;
return $this;
}
public function getWorkPhone(): ?string
{
return $this->workPhone;
}
public function setWorkPhone(string $workPhone): static
{
$this->workPhone = $workPhone;
return $this;
}
public function getFormattedPhone(): ?string
{
$ret = '';
if ($this->workPhone) {
$ret = '(' . substr($this->workPhone, 0, 3) . ') ' . substr($this->workPhone, 3, 3) . '-' . substr($this->workPhone, 6);
}
return $ret;
}
public function getSignature(): ?string
{
return $this->signature;
}
public function setSignature(?string $signature): static
{
$this->signature = $signature;
return $this;
}
public function isActive(): ?bool
{
return $this->active;
}
public function setActive(bool $active): static
{
$this->active = $active;
return $this;
}
public function getLastLogin(): ?\DateTimeInterface
{
return $this->lastLogin;
}
public function setLastLogin(?\DateTimeInterface $lastLogin): static
{
$this->lastLogin = $lastLogin;
return $this;
}
public function generateVCard(): string
{
list($fname, $lname) = explode(' ', $this->name, 2);
$b64image = null;
$fileExt = null;
if ($this->imageName) {
$fullFileName = dirname(dirname(__DIR__))."/public/{$_ENV['USER_IMAGE_PATH']}/{$this->imageName}";
$fileExt = strtoupper(pathinfo($fullFileName, PATHINFO_EXTENSION));
$b64image = base64_encode(
file_get_contents($fullFileName)
);
}
return 'BEGIN:VCARD' .
"\nVERSION:3.0" .
"\nN:{$lname};{$fname}" .
"\nFN:$this->name" .
"\nORG:{$this->company->getName()}" .
($this->workPhone ? "\nTEL;TYPE=WORK,VOICE:$this->workPhone" : null) .
($this->email ? "\nEMAIL;TYPE=WORK,INTERNET:$this->email" : null) .
"\nREV:" . date('c') .
($this->imageName ? "\nPHOTO;TYPE={$fileExt};ENCODING=b:{$b64image}" : null) .
"\nEND:VCARD";
}
/**
* @return Collection<int, Subscription>
*/
public function getSubscriptions(): Collection
{
return $this->subscriptions;
}
public function addSubscription(Subscription $subscription): static
{
if (!$this->subscriptions->contains($subscription)) {
$this->subscriptions->add($subscription);
$subscription->setUser($this);
}
return $this;
}
public function removeSubscription(Subscription $subscription): static
{
if ($this->subscriptions->removeElement($subscription)) {
// set the owning side to null (unless already changed)
if ($subscription->getUser() === $this) {
$subscription->setUser(null);
}
}
return $this;
}
}

View File

@ -1,8 +1,9 @@
<?php
namespace App\Entity;
namespace App\Entity\System;
use App\Repository\UserCaseRepository;
use App\Entity\Case\MemberCase;
use App\Repository\System\UserCaseRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: UserCaseRepository::class)]
@ -49,4 +50,9 @@ class UserCase
return $this;
}
public static function checkLevel(User $user, MemberCase $case): bool
{
return ($user->getLevel()->value >= $case->getLevel()->value);
}
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Enums\Case;
enum CaseLevel: int
{
case PARAPROFESSIONAL = 0;
case BACHELOR = 1;
case MASTER = 2;
case DOCTORATE = 3;
case ADMIN = 99;
}

View File

@ -1,6 +1,6 @@
<?php
namespace App\Enums;
namespace App\Enums\Case;
enum DischargeReason: string
{

View File

@ -0,0 +1,36 @@
<?php
namespace App\Enums\Case;
enum NoteLocation: string
{
case AGENCY_OTHER_PROFESSIONAL = 'Agency/Other Professional';
case AT_HOME = 'At Home';
case CHILDPLACE = 'Childplace';
case CHURCH = 'Church';
case CLIENT_HOME = 'Client Home';
case CLIENT_SEARCH = 'Client Search';
case COMMUNITY_OUTING = 'Community Outing';
case COURT_HOUSE = 'Court House';
case DCS_OFFICE = 'DCS Office';
case DENTIST_EYE_APPOINTMENT = 'Dentist/Eye appointment';
case DOCTOR_DENTIST_APPOINTMENT = 'Doctor/Dentist Appointment';
case EMPLOYMENT_SEARCH = 'Employment Search';
case FOOD_PANTRY = 'Food Pantry';
case FOSTER_HOME = 'Foster home';
case HOUSING_SEARCH = 'Housing Search';
case JAIL_CORRECTIONAL_FACILITY = 'Jail/Correctional Facility';
case LIBRARY = 'Library';
case OTHER = 'Other';
case PARK = 'Park';
case PROBATION_OFFICE = 'Probation Office';
case RELATIVE_HOME = 'Relative home';
case RESTAURANT = 'Restaurant';
case SCHOOL = 'School';
case SHOPPING_CENTER = 'Shopping Center';
case TELEPHONE = 'Telephone';
case TEXT_MESSAGE = 'Text Message';
case THERAPY_APPOINTMENT = 'Therapy Appointment';
case VEHICLE_TRANSPORTATION = 'Vehicle/Transportation';
case WELLSTONE = 'Wellstone';
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Enums\Case;
enum NoteMethod: int
{
case DCS_PROBATION_CONTACT = 0;
case BILLABLE = 1;
case BILLABLE_CASE_CONFERENCE = 2;
case BILLABLE_CFTM = 3;
case BILLABLE_COURT = 4;
case BILLABLE_CRISIS_PHONE_CALL = 6;
case BILLABLE_FACE_TO_FACE = 7;
case BILLABLE_PA_DENIED_BY_MEDIACID_SERVICES_TO_BE_PAID_BY_DCS = 8;
case BILLABLE_REPORT_WRITING = 9;
case BILLABLE_SUPERVISED_VISIT = 10;
case BILLABLE_TESTING_INTERPRETATION = 11;
case BILLED_TO_MEDIACID_INSURANCE = 12;
case CANCEL_BY_CLIENT = 13;
case CANCEL_BY_PROVIDER = 14;
case COLLATERAL = 15;
case NO_SHOW = 16;
case NON_BILLABLE = 17;
case SUPERVISED_VISIT_PRIVATE = 18;
}

View File

@ -0,0 +1,15 @@
<?php
namespace App\Enums\Case;
enum NoteStatus: string
{
case DRAFT = 'draft';
case IN_PROGRESS = 'in progress';
case IN_REVIEW = 'in review';
case PUBLISHED = 'published';
case SUBMITTED = 'submitted';
case APPROVED = 'approved';
case REJECTED = 'rejected';
case PAID = 'paid';
}

View File

@ -1,6 +1,6 @@
<?php
namespace App\Enums;
namespace App\Enums\Case;
enum RaceType: string
{

View File

@ -1,10 +1,11 @@
<?php
namespace App\Enums;
namespace App\Enums\Case;
enum ReferralServiceType: string
{
case FE_FF = 'FE-FF';
case VS_THBB = 'VS-THBB';
case VS_THBBT = 'VS-THBBT';
case VS_THBBCT = 'VS-THBBCT';
}

View File

@ -0,0 +1,9 @@
<?php
namespace App\Enums\Case;
enum ReferralType: string
{
case DCS = 'DCS';
case PO = 'PO';
}

View File

@ -1,6 +1,6 @@
<?php
namespace App\Enums;
namespace App\Enums\Case;
enum RelationshipType: string
{

View File

@ -0,0 +1,13 @@
<?php
namespace App\Enums\Case;
enum ResourceType: int
{
case FOOD_PANTRY = 0;
case CLOTHES_CLOSET = 1;
case JOB_OPENINGS = 2;
case HOUSING = 3;
case PARENT_SUPPORT = 4;
case PLAY_AREA = 5;
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Enums\Case;
enum VisitQualityLevel: int
{
case RARELY = 0;
case OFTEN = 1;
case OCCASIONALLY = 2;
case ALWAYS = 3;
}

View File

@ -1,12 +0,0 @@
<?php
namespace App\Enums;
enum CaseLevel: string
{
case PARAPROFESSIONAL = 'Paraprofessional';
case BACHELOR = 'Bachelor';
case MASTER = 'Master';
case DOCTORATE = 'Doctorate';
case ADMIN = 'Admin';
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Enums\Company;
enum DocumentExtras: int
{
case CLIENT_NAME = 0;
case CLIENT_SIGNATURE = 1;
case NAMES = 2;
case EMAIL = 3;
case PHONE = 4;
case RELATIONSHIP = 5;
case DATE = 6;
case EVENT_DETAILS = 7;
case ACTION_TAKEN = 8;
case COMMENTS = 9;
case PROVIDER_NAME = 10;
case PROVIDER_SIGNATURE = 11;
}

View File

@ -1,6 +1,6 @@
<?php
namespace App\Enums;
namespace App\Enums\System;
enum County: string
{

View File

@ -1,6 +1,6 @@
<?php
namespace App\Enums;
namespace App\Enums\System;
enum GenderType: string
{

View File

@ -1,6 +1,6 @@
<?php
namespace App\Enums;
namespace App\Enums\System;
enum JobType: string
{

View File

@ -0,0 +1,18 @@
<?php
namespace App\Enums\System;
enum MessageType: int
{
case GENERAL = 0;
case CASE = 1;
case STAFFING = 2;
case BILLING = 3;
case NEW_CASE = 4;
case USER = 5;
case NEW_REFERRAL = 6;
case STAFF_NOTE = 7;
case CALENDAR = 97;
case REMINDER = 98;
case UNKNOWN = 99;
}

Some files were not shown because too many files have changed in this diff Show More