mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-11-07 12:48:24 +00:00
Compare commits
285 Commits
v4.5.1
...
ticket-app
| Author | SHA1 | Date | |
|---|---|---|---|
| 41a31944b3 | |||
| 51607572de | |||
| 1fc5530707 | |||
|
|
b31778c068 | ||
|
305c6deb24
|
|||
|
d691098a21
|
|||
| 3a4c20b53d | |||
| b0c86e238d | |||
| d7614aeab2 | |||
| 671ed21d59 | |||
| 4b9db6ceb6 | |||
| c79c39b562 | |||
| bf768b8e99 | |||
| 2df01833ad | |||
| ffb8183d4d | |||
| 5d45339bf7 | |||
| e87e5cbbaf | |||
| fa8e92ebf5 | |||
| b7a92bf656 | |||
| 3dbbda7b64 | |||
| 769d76a0cc | |||
| 722b37fbcc | |||
| bf38ec22c9 | |||
| 3d99c0f561 | |||
| 2221d17930 | |||
| 9c2abb2dfa | |||
| 94744b9542 | |||
| f42bb498e4 | |||
| 01889ac671 | |||
| 62e5842311 | |||
| a22cbe0239 | |||
| 98902bdeb8 | |||
| 4765d4fe28 | |||
|
|
30bcb85549 | ||
|
8ad6f397a8
|
|||
| d713704633 | |||
| b1fa9242a0 | |||
| 6ac554f93a | |||
| 372d8e5825 | |||
| 10f05e5559 | |||
| ddb2a65419 | |||
| 8d40a8089f | |||
| e1bf4a24d2 | |||
| 208a378185 | |||
| 9089c8959b | |||
|
1b9b581c31
|
|||
| aa1abe4c88 | |||
| d82c9cc9a7 | |||
| a7e3b1c5d2 | |||
| 84cf11933d | |||
| bc2fbee5c6 | |||
| ebd10ca522 | |||
|
d3a31be412
|
|||
|
d159a82f88
|
|||
|
6d2e78ce55
|
|||
| 61ca700bbe | |||
|
|
b43aeebc3c | ||
| 056e2dcc5f | |||
| e57d1ac696 | |||
| 0eff1d2e79 | |||
| 3928b2cc7a | |||
|
4f51ef81ad
|
|||
|
4637dc692c
|
|||
| 38935edb93 | |||
|
|
e1ef65d4ca | ||
| ec9d0be70b | |||
|
|
0ba2cbc1e8 | ||
| e87429933a | |||
|
8e2e676e3d
|
|||
| e12ad563a3 | |||
|
|
711aa8db9b | ||
| e78d44953f | |||
| 18f67801c7 | |||
|
c815e6bc69
|
|||
| 807f2711fe | |||
|
|
cd594cd580 | ||
|
fb6b26bfb5
|
|||
|
c5cedb8bd6
|
|||
|
2665e43a61
|
|||
|
25561cdf63
|
|||
| 10b73e06e1 | |||
|
|
e7c04e34a9 | ||
| 164beee7c6 | |||
|
|
4d96eb9457 | ||
| fe2eba3b29 | |||
|
|
61d1232e31 | ||
| 6594d4f6a6 | |||
| 1a66a9e864 | |||
| 1b74c119dc | |||
| 14d88810f3 | |||
| 445a2c9358 | |||
| c8baf0a8aa | |||
| faed443a96 | |||
| bbf387d96f | |||
|
|
b7c9b60744 | ||
|
2bd303bbbe
|
|||
|
c5e6122d2c
|
|||
| 088b876e20 | |||
| 3400656d7c | |||
|
568c8be7fd
|
|||
|
538ecc42ea
|
|||
|
15d26d4b06
|
|||
|
d8bd9bd7cd
|
|||
|
dcdfba5ccd
|
|||
|
0204bdd38d
|
|||
|
392fd01b56
|
|||
| 35844f3b73 | |||
| 7506b918d7 | |||
| cfba291f2c | |||
|
|
04438c09d3 | ||
| 2a54d1b909 | |||
|
|
628eeac5e0 | ||
| a2263b3fa1 | |||
| 74796d0fb0 | |||
|
c19481e40a
|
|||
|
|
6eeb717b1a | ||
|
beb7c462da
|
|||
|
|
dbf363a9e8 | ||
|
64a2f7c9ed
|
|||
| f26d9739c8 | |||
|
afa5edc1d8
|
|||
|
42d6c9e672
|
|||
|
2b22d4cb7c
|
|||
|
c8e5d0eb37
|
|||
| 2bf8ad5d6c | |||
| 11698a52e3 | |||
| 70955573e8 | |||
|
|
3df4043eb9 | ||
|
06e8264dde
|
|||
| b451d2c4a3 | |||
| 4f93150874 | |||
| 0566ab0910 | |||
|
|
f4eeee1598 | ||
| 33cf16fc13 | |||
| 0a331aab37 | |||
| d43b739654 | |||
| c72432efae | |||
|
95975fae55
|
|||
|
95a7efa138
|
|||
|
45e193ff6d
|
|||
|
dfc146ff3f
|
|||
| b41fcf66a9 | |||
|
|
a8dd1b3548 | ||
|
2b99a480ac
|
|||
|
7633e587bb
|
|||
|
fc61dfdf3a
|
|||
|
f1a5b5c49e
|
|||
|
ec685dcd47
|
|||
|
631ae3eedd
|
|||
|
440a7837ac
|
|||
|
e0abf34784
|
|||
|
377ae9a9dc
|
|||
|
034dc30e30
|
|||
|
d615111a0f
|
|||
|
ffb756c712
|
|||
|
69daccb860
|
|||
|
16435423cf
|
|||
|
697b4ab436
|
|||
|
67d804e28e
|
|||
|
cf41fa9574
|
|||
|
b8b325f7d7
|
|||
|
e97bd8c4ef
|
|||
|
e28d7df533
|
|||
|
4b20b1bc01
|
|||
|
b15733076c
|
|||
|
25be5c9ea3
|
|||
|
b035020c6f
|
|||
|
128101dc46
|
|||
|
5f2711023e
|
|||
|
bdf2ed4bbd
|
|||
|
1df542603e
|
|||
|
80bcc68ce5
|
|||
|
154fc3e2f6
|
|||
|
e45af94c78
|
|||
|
166a6fde20
|
|||
|
631f047338
|
|||
|
a777588bb8
|
|||
|
ca78d112c2
|
|||
|
bcfd317d83
|
|||
|
348740f073
|
|||
|
0d74f0980f
|
|||
|
be19dc00db
|
|||
|
643028ffd6
|
|||
|
ac4e2e5bf2
|
|||
|
498572b96e
|
|||
|
d2a61ce69b
|
|||
|
a9c0567ee1
|
|||
|
76cec5b5a8
|
|||
|
efe8a67697
|
|||
|
26dfa9b028
|
|||
|
50025044d3
|
|||
|
e6202a2e34
|
|||
|
b863bd967d
|
|||
|
e65bcf7275
|
|||
|
e00ece4200
|
|||
|
640fd71402
|
|||
|
aae50ca290
|
|||
|
1fa483598b
|
|||
|
e4b6a468f8
|
|||
|
|
66c7758023 | ||
|
|
4750d2c24e | ||
|
|
ca05e3d979 | ||
|
|
a20f9b4f86 | ||
|
|
c73c1eb8d5 | ||
|
|
8778bb0731 | ||
|
|
c7d20eebc5 | ||
|
|
b9e130c159 | ||
|
|
3e8bc94af3 | ||
|
|
0c914c9f9f | ||
|
|
580a60c939 | ||
|
|
4996ac3b7c | ||
|
|
2a23bf19cb | ||
|
|
650d2596d9 | ||
|
|
2bdd5a329e | ||
|
78d1776733
|
|||
|
66dc603c85
|
|||
|
3a8154ecce
|
|||
|
c81828e04f
|
|||
|
|
ec17dd7de2 | ||
| 76c076a5f3 | |||
|
|
f0045edd6c | ||
|
|
d00b76ffcd | ||
|
|
8991f0ef3f | ||
|
|
d6f5eae0c9 | ||
|
|
821fce3dd8 | ||
|
|
1d33ae1e39 | ||
|
|
19af0feb57 | ||
|
|
1c09e9a692 | ||
|
|
d72e748388 | ||
|
|
ab850b7b70 | ||
|
|
3f9745d8cf | ||
|
|
473765366a | ||
|
|
6500c24a7f | ||
|
|
1d00457141 | ||
|
|
eb0bf56cff | ||
|
|
7b8cd90cf1 | ||
|
|
a27d92aba0 | ||
|
|
85bdfb9e21 | ||
|
|
4cffcf4de1 | ||
|
|
b2587a688f | ||
|
|
c9f0e9843b | ||
|
|
b40ad9e445 | ||
|
|
3e10e47e29 | ||
|
|
2a1963e993 | ||
| 34c171659b | |||
|
2d8b960d9e
|
|||
| 831ae03431 | |||
|
45828174d1
|
|||
|
ed45f14a45
|
|||
|
fa67835690
|
|||
|
b434d38091
|
|||
|
|
800a952532 | ||
|
9f355032a8
|
|||
|
0bc6e62d4d
|
|||
|
46fb1c04b5
|
|||
| 3b2c3d1464 | |||
|
|
0bd6038160 | ||
|
|
baab8e94ce | ||
|
e2deb55fdb
|
|||
|
|
2cdfb50058 | ||
|
39d701feb2
|
|||
|
613ee8b186
|
|||
|
56a1a488de
|
|||
| 3f789ad0f4 | |||
|
467bea7cde
|
|||
|
670b8eb82b
|
|||
|
a9760b323f
|
|||
|
71a3a1924a
|
|||
|
ecdc1e25bf
|
|||
|
dd37427be1
|
|||
|
c8467df1b1
|
|||
|
4c89a954fa
|
|||
|
7c1f3b114d
|
|||
|
36bc4dab24
|
|||
|
4b30d92282
|
|||
|
75fbec5489
|
|||
|
912fdd6349
|
|||
|
5832542978
|
|||
|
5c3585a1ed
|
|||
|
a2f1e20ddf
|
|||
|
4d67702a76
|
|||
| 18e442db29 | |||
|
|
deb3d92189 | ||
|
a59ea7db31
|
|||
|
a738b0cac9
|
7
.changes/unreleased/DX-20251027-150053.yaml
Normal file
7
.changes/unreleased/DX-20251027-150053.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
kind: DX
|
||||||
|
body: |
|
||||||
|
Send notifications log to dedicated channel, if it exists
|
||||||
|
time: 2025-10-27T15:00:53.309372316+01:00
|
||||||
|
custom:
|
||||||
|
Issue: ""
|
||||||
|
SchemaChange: No schema change
|
||||||
6
.changes/unreleased/Feature-20240530-160003.yaml
Normal file
6
.changes/unreleased/Feature-20240530-160003.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Feature
|
||||||
|
body: |
|
||||||
|
Upgrade import of address list to the last version of compiled addresses of belgian-best-address
|
||||||
|
time: 2024-05-30T16:00:03.440767606+02:00
|
||||||
|
custom:
|
||||||
|
Issue: ""
|
||||||
6
.changes/unreleased/Feature-20240531-190242.yaml
Normal file
6
.changes/unreleased/Feature-20240531-190242.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Feature
|
||||||
|
body: |
|
||||||
|
Upgrade CKEditor and refactor configuration with use of typescript
|
||||||
|
time: 2024-05-31T19:02:42.776662753+02:00
|
||||||
|
custom:
|
||||||
|
Issue: ""
|
||||||
6
.changes/unreleased/Feature-20250808-120802.yaml
Normal file
6
.changes/unreleased/Feature-20250808-120802.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Feature
|
||||||
|
body: Create invitation list in user menu
|
||||||
|
time: 2025-08-08T12:08:02.446361367+02:00
|
||||||
|
custom:
|
||||||
|
Issue: "385"
|
||||||
|
SchemaChange: No schema change
|
||||||
6
.changes/unreleased/Feature-20251007-155945.yaml
Normal file
6
.changes/unreleased/Feature-20251007-155945.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Feature
|
||||||
|
body: Admin interface for Motive entity
|
||||||
|
time: 2025-10-07T15:59:45.597029709+02:00
|
||||||
|
custom:
|
||||||
|
Issue: ""
|
||||||
|
SchemaChange: No schema change
|
||||||
6
.changes/unreleased/Feature-20251022-111552.yaml
Normal file
6
.changes/unreleased/Feature-20251022-111552.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Feature
|
||||||
|
body: Add an admin interface for Motive entity
|
||||||
|
time: 2025-10-22T11:15:52.13937955+02:00
|
||||||
|
custom:
|
||||||
|
Issue: ""
|
||||||
|
SchemaChange: Add columns or tables
|
||||||
6
.changes/unreleased/Feature-20251029-152510.yaml
Normal file
6
.changes/unreleased/Feature-20251029-152510.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Feature
|
||||||
|
body: Add columns for comments linked to an activity in the activity list export
|
||||||
|
time: 2025-10-29T15:25:10.493968528+01:00
|
||||||
|
custom:
|
||||||
|
Issue: "404"
|
||||||
|
SchemaChange: No schema change
|
||||||
6
.changes/unreleased/Fixed-20251029-124355.yaml
Normal file
6
.changes/unreleased/Fixed-20251029-124355.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: 'Fix: display also social actions linked to parents of the selected social issue'
|
||||||
|
time: 2025-10-29T12:43:55.008647232+01:00
|
||||||
|
custom:
|
||||||
|
Issue: "451"
|
||||||
|
SchemaChange: No schema change
|
||||||
6
.changes/unreleased/Fixed-20251029-143836.yaml
Normal file
6
.changes/unreleased/Fixed-20251029-143836.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: 'Fix: export actions and their results in csv even when action does not have any goals attached to it.'
|
||||||
|
time: 2025-10-29T14:38:36.195220844+01:00
|
||||||
|
custom:
|
||||||
|
Issue: "453"
|
||||||
|
SchemaChange: No schema change
|
||||||
6
.changes/unreleased/Fixed-20251104-135108.yaml
Normal file
6
.changes/unreleased/Fixed-20251104-135108.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: Fix the possibility to delete a workflow
|
||||||
|
time: 2025-11-04T13:51:08.113234488+01:00
|
||||||
|
custom:
|
||||||
|
Issue: ""
|
||||||
|
SchemaChange: Drop or rename table or columns, or enforce new constraint that must be manually fixed
|
||||||
6
.changes/unreleased/Fixed-20251106-161605.yaml
Normal file
6
.changes/unreleased/Fixed-20251106-161605.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: Fix suggestion of referrer when creating notification for accompanyingPeriodWorkDocument
|
||||||
|
time: 2025-11-06T16:16:05.861813041+01:00
|
||||||
|
custom:
|
||||||
|
Issue: "428"
|
||||||
|
SchemaChange: No schema change
|
||||||
6
.changes/unreleased/UX-20251006-123932.yaml
Normal file
6
.changes/unreleased/UX-20251006-123932.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: UX
|
||||||
|
body: Change the terms 'cercle' and 'centre' to 'service', and 'territoire' respectively.
|
||||||
|
time: 2025-10-06T12:39:32.514056818+02:00
|
||||||
|
custom:
|
||||||
|
Issue: "425"
|
||||||
|
SchemaChange: No schema change
|
||||||
6
.changes/unreleased/UX-20251029-110804.yaml
Normal file
6
.changes/unreleased/UX-20251029-110804.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: UX
|
||||||
|
body: Improve the ux for selecting whether user wants to be notified of the final step of a workflow or all steps
|
||||||
|
time: 2025-10-29T11:08:04.077020411+01:00
|
||||||
|
custom:
|
||||||
|
Issue: "542"
|
||||||
|
SchemaChange: No schema change
|
||||||
6
.changes/unreleased/UX-20251030-180919.yaml
Normal file
6
.changes/unreleased/UX-20251030-180919.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: UX
|
||||||
|
body: Expand timeSpent choices for evaluation document and translate them to user locale or fallback 'fr'
|
||||||
|
time: 2025-10-30T18:09:19.373907522+01:00
|
||||||
|
custom:
|
||||||
|
Issue: ""
|
||||||
|
SchemaChange: No schema change
|
||||||
14
.changes/v4.6.0.md
Normal file
14
.changes/v4.6.0.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
## v4.6.0 - 2025-10-15
|
||||||
|
### Feature
|
||||||
|
* ([#423](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/423)) Create environment banner that can be activated and configured depending on the image deployed
|
||||||
|
* ([#394](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/394)) Only show active workflow on the page "my tracked workflow"
|
||||||
|
### Fixed
|
||||||
|
* Fix loading of classLists in SocialIssuesAcc.vue, ensure elements are present
|
||||||
|
* Fix the rendering of list of StoredObjectVersions, where there are kept version (before converting to pdf) and intermediate versions deleted
|
||||||
|
* ([#434](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/434)) Notification: fix editing of sent notification by removing form.addressesEmails, a field that no longer exists
|
||||||
|
* Fix loading of social issues and social actions within vue component
|
||||||
|
* ([#446](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/446)) Add unique condition on stored object filename, with cleaning step on existing duplicate filenames
|
||||||
|
|
||||||
|
**Schema Change**: Drop or rename table or columns, or enforce new constraint that must be manually fixed
|
||||||
|
* [workflow] take permissions into account to delete the workflow attachment
|
||||||
|
* ([#448](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/448)) Fix the execution of daily cronjob notification, when the previous last execution storage was invalid
|
||||||
3
.changes/v4.6.1.md
Normal file
3
.changes/v4.6.1.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
## v4.6.1 - 2025-10-27
|
||||||
|
### Fixed
|
||||||
|
* Fix export case where no 'reason' is picked within the PersonHavingActivityBetweenDateFilter.php
|
||||||
@@ -19,11 +19,11 @@ max_line_length = 80
|
|||||||
[COMMIT_EDITMSG]
|
[COMMIT_EDITMSG]
|
||||||
max_line_length = 0
|
max_line_length = 0
|
||||||
|
|
||||||
[*.{js, vue, ts}]
|
[*.{js,vue,ts}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
indent_style = space
|
indent_style = space
|
||||||
|
|
||||||
[.rst]
|
[*.rst]
|
||||||
ident_size = 3
|
indent_size = 3
|
||||||
ident_style = space
|
indent_style = space
|
||||||
|
|
||||||
|
|||||||
@@ -234,14 +234,9 @@ This must be a decision made by a human, not by an AI. Every AI task must abort
|
|||||||
|
|
||||||
#### Running Tests
|
#### Running Tests
|
||||||
|
|
||||||
The tests are run from the project's root (not from the bundle's root).
|
The tests are run from the project's root (not from the bundle's root: so, do not change the directory to any bundle directory before running tests).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run all tests
|
|
||||||
vendor/bin/phpunit
|
|
||||||
|
|
||||||
# Run tests for a specific bundle
|
|
||||||
vendor/bin/phpunit --testsuite NameBundle
|
|
||||||
|
|
||||||
# Run a specific test file
|
# Run a specific test file
|
||||||
vendor/bin/phpunit path/to/TestFile.php
|
vendor/bin/phpunit path/to/TestFile.php
|
||||||
@@ -250,6 +245,9 @@ vendor/bin/phpunit path/to/TestFile.php
|
|||||||
vendor/bin/phpunit --filter methodName path/to/TestFile.php
|
vendor/bin/phpunit --filter methodName path/to/TestFile.php
|
||||||
```
|
```
|
||||||
|
|
||||||
|
When writing tests, only test specific files. Do not run all tests or the full
|
||||||
|
test suite.
|
||||||
|
|
||||||
#### Test Structure
|
#### Test Structure
|
||||||
|
|
||||||
Tests are organized by bundle and follow the same structure as the bundle itself:
|
Tests are organized by bundle and follow the same structure as the bundle itself:
|
||||||
|
|||||||
4
.prettierrc
Normal file
4
.prettierrc
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false
|
||||||
|
}
|
||||||
30
.vscode/launch.json
vendored
Normal file
30
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Chill Debug",
|
||||||
|
"type": "php",
|
||||||
|
"request": "launch",
|
||||||
|
"port": 9000,
|
||||||
|
"pathMappings": {
|
||||||
|
"/var/www/html": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
"preLaunchTask": "symfony"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Yarn Encore Dev (Watch)",
|
||||||
|
"type": "node-terminal",
|
||||||
|
"request": "launch",
|
||||||
|
"command": "yarn encore dev --watch",
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"compounds": [
|
||||||
|
{
|
||||||
|
"name": "Chill Debug + Yarn Encore Dev (Watch)",
|
||||||
|
"configurations": ["Chill Debug", "Yarn Encore Dev (Watch)"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
23
.vscode/tasks.json
vendored
Normal file
23
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "shell",
|
||||||
|
"command": "symfony",
|
||||||
|
"args": [
|
||||||
|
"server:start",
|
||||||
|
"--allow-http",
|
||||||
|
"--no-tls",
|
||||||
|
"--port=8000",
|
||||||
|
"--allow-all-ip",
|
||||||
|
"-d"
|
||||||
|
],
|
||||||
|
"label": "symfony"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "shell",
|
||||||
|
"command": "yarn",
|
||||||
|
"args": ["encore", "dev", "--watch"],
|
||||||
|
"label": "webpack"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
403
CHANGELOG.md
403
CHANGELOG.md
@@ -6,59 +6,78 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
|
|||||||
and is generated by [Changie](https://github.com/miniscruff/changie).
|
and is generated by [Changie](https://github.com/miniscruff/changie).
|
||||||
|
|
||||||
|
|
||||||
|
## v4.6.1 - 2025-10-27
|
||||||
|
### Fixed
|
||||||
|
* Fix export case where no 'reason' is picked within the PersonHavingActivityBetweenDateFilter.php
|
||||||
|
|
||||||
|
## v4.6.0 - 2025-10-15
|
||||||
|
### Feature
|
||||||
|
* ([#423](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/423)) Create environment banner that can be activated and configured depending on the image deployed
|
||||||
|
* ([#394](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/394)) Only show active workflow on the page "my tracked workflow"
|
||||||
|
### Fixed
|
||||||
|
* Fix loading of classLists in SocialIssuesAcc.vue, ensure elements are present
|
||||||
|
* Fix the rendering of list of StoredObjectVersions, where there are kept version (before converting to pdf) and intermediate versions deleted
|
||||||
|
* ([#434](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/434)) Notification: fix editing of sent notification by removing form.addressesEmails, a field that no longer exists
|
||||||
|
* Fix loading of social issues and social actions within vue component
|
||||||
|
* ([#446](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/446)) Add unique condition on stored object filename, with cleaning step on existing duplicate filenames
|
||||||
|
|
||||||
|
**Schema Change**: Drop or rename table or columns, or enforce new constraint that must be manually fixed
|
||||||
|
* [workflow] take permissions into account to delete the workflow attachment
|
||||||
|
* ([#448](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/448)) Fix the execution of daily cronjob notification, when the previous last execution storage was invalid
|
||||||
|
|
||||||
## v4.5.1 - 2025-10-03
|
## v4.5.1 - 2025-10-03
|
||||||
### Fixed
|
### Fixed
|
||||||
* Add missing javascript dependency
|
* Add missing javascript dependency
|
||||||
* Add exception handling for conversion of attachment on sending external, when documens are already in pdf
|
* Add exception handling for conversion of attachment on sending external, when documens are already in pdf
|
||||||
|
|
||||||
## v4.5.0 - 2025-10-03
|
## v4.5.0 - 2025-10-03
|
||||||
### Feature
|
### Feature
|
||||||
* Only allow delete of attachment on workflows that are not final
|
* Only allow delete of attachment on workflows that are not final
|
||||||
* Move up signature buttons on index workflow page for easier access
|
* Move up signature buttons on index workflow page for easier access
|
||||||
* Filter out document from attachment list if it is the same as the workflow document
|
* Filter out document from attachment list if it is the same as the workflow document
|
||||||
* Block edition on attached document on workflow, if the workflow is finalized or sent external
|
* Block edition on attached document on workflow, if the workflow is finalized or sent external
|
||||||
* Convert workflow's attached document to pdf while sending them external
|
* Convert workflow's attached document to pdf while sending them external
|
||||||
* After a signature is canceled or rejected, going to a waiting page until the post-process routines apply a workflow transition
|
* After a signature is canceled or rejected, going to a waiting page until the post-process routines apply a workflow transition
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#426](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/426)) Increased the number of required characters when setting a new password in Chill from 9 to 14 - GDPR compliance
|
* ([#426](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/426)) Increased the number of required characters when setting a new password in Chill from 9 to 14 - GDPR compliance
|
||||||
* Fix permissions on storedObject which are subject by a workflow
|
* Fix permissions on storedObject which are subject by a workflow
|
||||||
### DX
|
### DX
|
||||||
* Introduce a WaitingScreen component to display a waiting screen
|
* Introduce a WaitingScreen component to display a waiting screen
|
||||||
|
|
||||||
## v4.4.2 - 2025-09-12
|
## v4.4.2 - 2025-09-12
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix document generation and workflow generation do not work on accompanying period work documents
|
* Fix document generation and workflow generation do not work on accompanying period work documents
|
||||||
|
|
||||||
## v4.4.1 - 2025-09-11
|
## v4.4.1 - 2025-09-11
|
||||||
### Fixed
|
### Fixed
|
||||||
* fix translations in duplicate evaluation document modal and realign close modal button
|
* fix translations in duplicate evaluation document modal and realign close modal button
|
||||||
|
|
||||||
## v4.4.0 - 2025-09-11
|
## v4.4.0 - 2025-09-11
|
||||||
### Feature
|
### Feature
|
||||||
* ([#359](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/359)) Allow the merge of two accompanying period works
|
* ([#359](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/359)) Allow the merge of two accompanying period works
|
||||||
* ([#369](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/369)) Duplication of a document to another accompanying period work evaluation
|
* ([#369](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/369)) Duplication of a document to another accompanying period work evaluation
|
||||||
* ([#359](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/359)) Fusion of two accompanying period works
|
* ([#359](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/359)) Fusion of two accompanying period works
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix display of 'duplicate' and 'merge' buttons in CRUD templates
|
* Fix display of 'duplicate' and 'merge' buttons in CRUD templates
|
||||||
* Fix saving notification preferences in user's profile
|
* Fix saving notification preferences in user's profile
|
||||||
|
|
||||||
## v4.3.0 - 2025-09-08
|
## v4.3.0 - 2025-09-08
|
||||||
### Feature
|
### Feature
|
||||||
* ([#409](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/409)) Add 45 and 60 min calendar ranges
|
* ([#409](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/409)) Add 45 and 60 min calendar ranges
|
||||||
* Add a command to generate a list of permissions
|
* Add a command to generate a list of permissions
|
||||||
* ([#412](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/412)) Add an absence end date
|
* ([#412](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/412)) Add an absence end date
|
||||||
|
|
||||||
**Schema Change**: Add columns or tables
|
**Schema Change**: Add columns or tables
|
||||||
### Fixed
|
### Fixed
|
||||||
* fix date formatting in calendar range display
|
* fix date formatting in calendar range display
|
||||||
* Change route URL to avoid clash with person duplicate controller method
|
* Change route URL to avoid clash with person duplicate controller method
|
||||||
|
|
||||||
## v4.2.1 - 2025-09-03
|
## v4.2.1 - 2025-09-03
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix exports to work with DirectExportInterface
|
* Fix exports to work with DirectExportInterface
|
||||||
### DX
|
### DX
|
||||||
* Improve error message when a stored object cannot be written on local disk
|
* Improve error message when a stored object cannot be written on local disk
|
||||||
|
|
||||||
|
|
||||||
## v4.2.0 - 2025-09-02
|
## v4.2.0 - 2025-09-02
|
||||||
### Feature
|
### Feature
|
||||||
@@ -73,26 +92,26 @@ and is generated by [Changie](https://github.com/miniscruff/changie).
|
|||||||
|
|
||||||
## v4.1.0 - 2025-08-26
|
## v4.1.0 - 2025-08-26
|
||||||
### Feature
|
### Feature
|
||||||
* ([#400](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/400)) Add filter to social actions list to filter out actions where current user intervenes
|
* ([#400](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/400)) Add filter to social actions list to filter out actions where current user intervenes
|
||||||
* ([#399](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/399)) Show filters on list pages unfolded by default
|
* ([#399](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/399)) Show filters on list pages unfolded by default
|
||||||
* Expansion of event module with new fields in the creation form: thematic, internal/external animator, responsable, and budget elements. Filtering options in the event list + adapted exports
|
* Expansion of event module with new fields in the creation form: thematic, internal/external animator, responsable, and budget elements. Filtering options in the event list + adapted exports
|
||||||
|
|
||||||
**Schema Change**: Add columns or tables
|
**Schema Change**: Add columns or tables
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#382](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/382)) adjust display logic for accompanying period dates, include closing date if period is closed.
|
* ([#382](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/382)) adjust display logic for accompanying period dates, include closing date if period is closed.
|
||||||
* ([#384](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/384)) add min and step attributes to integer field in DateIntervalType
|
* ([#384](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/384)) add min and step attributes to integer field in DateIntervalType
|
||||||
### UX
|
### UX
|
||||||
* Limit display of participations in event list
|
* Limit display of participations in event list
|
||||||
|
|
||||||
## v4.0.2 - 2025-07-09
|
## v4.0.2 - 2025-07-09
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix add missing translation
|
* Fix add missing translation
|
||||||
* Fix the transfer of evaluations and documents during of accompanyingperiodwork
|
* Fix the transfer of evaluations and documents during of accompanyingperiodwork
|
||||||
|
|
||||||
## v4.0.1 - 2025-07-08
|
## v4.0.1 - 2025-07-08
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix package.json for compilation
|
* Fix package.json for compilation
|
||||||
|
|
||||||
|
|
||||||
## v4.0.0 - 2025-07-08
|
## v4.0.0 - 2025-07-08
|
||||||
### Feature
|
### Feature
|
||||||
@@ -171,30 +190,30 @@ framework:
|
|||||||
|
|
||||||
## v3.12.1 - 2025-06-30
|
## v3.12.1 - 2025-06-30
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix loading of the list of documents
|
* Fix loading of the list of documents
|
||||||
|
|
||||||
## v3.12.0 - 2025-06-30
|
## v3.12.0 - 2025-06-30
|
||||||
### Feature
|
### Feature
|
||||||
* ([#377](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/377)) Add the document file name to the document title when a user upload a document, unless there is already a document title.
|
* ([#377](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/377)) Add the document file name to the document title when a user upload a document, unless there is already a document title.
|
||||||
* Add desactivation date for social action and issue csv export
|
* Add desactivation date for social action and issue csv export
|
||||||
* Add Emoji and Fullscreen feature to ckeditor configuration
|
* Add Emoji and Fullscreen feature to ckeditor configuration
|
||||||
* ([#321](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/321)) Create editor which allow us to toggle between rich and simple text editor
|
* ([#321](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/321)) Create editor which allow us to toggle between rich and simple text editor
|
||||||
* Do not remove workflow which are automatically canceled after staling for more than 30 days
|
* Do not remove workflow which are automatically canceled after staling for more than 30 days
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#376](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/376)) trying to prevent bug of typeerror in doc-history + improved display of document history
|
* ([#376](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/376)) trying to prevent bug of typeerror in doc-history + improved display of document history
|
||||||
* ([#381](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/381)) Display previous participation in acc course work even if the person has left the acc course
|
* ([#381](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/381)) Display previous participation in acc course work even if the person has left the acc course
|
||||||
* ([#372](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/372)) Fix display of text in calendar events
|
* ([#372](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/372)) Fix display of text in calendar events
|
||||||
* Add missing translation for user_group.no_user_groups
|
* Add missing translation for user_group.no_user_groups
|
||||||
* Fix admin entity edit actions for event admin entities and activity reason (category) entities
|
* Fix admin entity edit actions for event admin entities and activity reason (category) entities
|
||||||
* ([#392](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/392)) Allow null and cast as string to setContent method for NewsItem
|
* ([#392](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/392)) Allow null and cast as string to setContent method for NewsItem
|
||||||
|
|
||||||
* ([#393](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/393)) Doc Generation: the "dump only" method send the document as an email attachment.
|
* ([#393](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/393)) Doc Generation: the "dump only" method send the document as an email attachment.
|
||||||
### DX
|
### DX
|
||||||
* ([#352](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/352)) Remove dead code for wopi-link module
|
* ([#352](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/352)) Remove dead code for wopi-link module
|
||||||
* Replace library node-sass by sass, and upgrade bootstrap to version 5.3 (yarn upgrade / install is required)
|
* Replace library node-sass by sass, and upgrade bootstrap to version 5.3 (yarn upgrade / install is required)
|
||||||
### UX
|
### UX
|
||||||
* ([#374](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/374)) Remove default filter in_progress for the page 'my tasks'; Allows for new tasks to be displayed upon opening of the page
|
* ([#374](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/374)) Remove default filter in_progress for the page 'my tasks'; Allows for new tasks to be displayed upon opening of the page
|
||||||
* Improve labeling of fields in person resource creation form
|
* Improve labeling of fields in person resource creation form
|
||||||
|
|
||||||
## v3.11.0 - 2025-04-17
|
## v3.11.0 - 2025-04-17
|
||||||
### Feature
|
### Feature
|
||||||
@@ -218,11 +237,11 @@ framework:
|
|||||||
|
|
||||||
## v3.10.3 - 2025-03-18
|
## v3.10.3 - 2025-03-18
|
||||||
### DX
|
### DX
|
||||||
* Eslint fixes
|
* Eslint fixes
|
||||||
|
|
||||||
## v3.10.2 - 2025-03-17
|
## v3.10.2 - 2025-03-17
|
||||||
### Fixed
|
### Fixed
|
||||||
* Replace a ts-expect-error with a ts-ignore
|
* Replace a ts-expect-error with a ts-ignore
|
||||||
|
|
||||||
## v3.10.1 - 2025-03-17
|
## v3.10.1 - 2025-03-17
|
||||||
### DX
|
### DX
|
||||||
@@ -230,37 +249,37 @@ framework:
|
|||||||
|
|
||||||
## v3.10.0 - 2025-03-17
|
## v3.10.0 - 2025-03-17
|
||||||
### Feature
|
### Feature
|
||||||
* ([#363](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/363)) Display social actions grouped per social issue within activity form
|
* ([#363](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/363)) Display social actions grouped per social issue within activity form
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#362](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/362)) Fix Dependency Injection, which prevented to save the CalendarRange
|
* ([#362](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/362)) Fix Dependency Injection, which prevented to save the CalendarRange
|
||||||
* ([#368](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/368)) fix search query for user groups
|
* ([#368](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/368)) fix search query for user groups
|
||||||
|
|
||||||
## v3.9.2 - 2025-02-27
|
## v3.9.2 - 2025-02-27
|
||||||
### Fixed
|
### Fixed
|
||||||
* Use fetchResults method to fetch all social issues instead of only the first page
|
* Use fetchResults method to fetch all social issues instead of only the first page
|
||||||
|
|
||||||
## v3.9.1 - 2025-02-27
|
## v3.9.1 - 2025-02-27
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix post/patch request with missing 'type' property for gender
|
* Fix post/patch request with missing 'type' property for gender
|
||||||
|
|
||||||
## v3.9.0 - 2025-02-27
|
## v3.9.0 - 2025-02-27
|
||||||
### Feature
|
### Feature
|
||||||
* ([#349](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/349)) Suggest all referrers within actions of the accompanying period when creating an activity
|
* ([#349](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/349)) Suggest all referrers within actions of the accompanying period when creating an activity
|
||||||
* ([#343](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/343)) Add possibility to export a csv with all social issues and social actions
|
* ([#343](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/343)) Add possibility to export a csv with all social issues and social actions
|
||||||
* ([#360](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/360)) Restore document to previous kept version when a workflow is canceled
|
* ([#360](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/360)) Restore document to previous kept version when a workflow is canceled
|
||||||
* ([#341](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/341)) Add a list of third parties from within the admin (csv download)
|
* ([#341](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/341)) Add a list of third parties from within the admin (csv download)
|
||||||
### Fixed
|
### Fixed
|
||||||
* fix generation of document with accompanying period context, and list of activities and works
|
* fix generation of document with accompanying period context, and list of activities and works
|
||||||
### DX
|
### DX
|
||||||
* ([#333](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/333)) Create an unique source of trust for translations
|
* ([#333](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/333)) Create an unique source of trust for translations
|
||||||
|
|
||||||
## v3.8.2 - 2025-02-10
|
## v3.8.2 - 2025-02-10
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#358](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/358)) Remove "filter" button on list of documents in the workflow's "add attachement" modal
|
* ([#358](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/358)) Remove "filter" button on list of documents in the workflow's "add attachement" modal
|
||||||
|
|
||||||
## v3.8.1 - 2025-02-05
|
## v3.8.1 - 2025-02-05
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix household link in the parcours banner
|
* Fix household link in the parcours banner
|
||||||
|
|
||||||
## v3.8.0 - 2025-02-03
|
## v3.8.0 - 2025-02-03
|
||||||
### Feature
|
### Feature
|
||||||
@@ -276,7 +295,7 @@ framework:
|
|||||||
|
|
||||||
## v3.7.1 - 2025-01-21
|
## v3.7.1 - 2025-01-21
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix legacy configuration processor for notifier component
|
* Fix legacy configuration processor for notifier component
|
||||||
|
|
||||||
## v3.7.0 - 2025-01-21
|
## v3.7.0 - 2025-01-21
|
||||||
### Feature
|
### Feature
|
||||||
@@ -343,33 +362,33 @@ chill_main:
|
|||||||
|
|
||||||
## v3.6.0 - 2025-01-16
|
## v3.6.0 - 2025-01-16
|
||||||
### Feature
|
### Feature
|
||||||
* Importer for addresses does not fails when the postal code is not found with some addresses, and compute a recap list of all addresses that could not be imported. This recap list can be send by email.
|
* Importer for addresses does not fails when the postal code is not found with some addresses, and compute a recap list of all addresses that could not be imported. This recap list can be send by email.
|
||||||
* ([#346](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/346)) Create a driver for storing documents on disk (instead of openstack object store)
|
* ([#346](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/346)) Create a driver for storing documents on disk (instead of openstack object store)
|
||||||
|
|
||||||
* Add address importer from french Base d'Adresse Nationale (BAN)
|
* Add address importer from french Base d'Adresse Nationale (BAN)
|
||||||
* ([#343](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/343)) Add csv export for social issues and social actions
|
* ([#343](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/343)) Add csv export for social issues and social actions
|
||||||
### Fixed
|
### Fixed
|
||||||
* Export: fix missing alias in activity between certain dates filter. Condition added for alias.
|
* Export: fix missing alias in activity between certain dates filter. Condition added for alias.
|
||||||
|
|
||||||
## v3.5.3 - 2025-01-07
|
## v3.5.3 - 2025-01-07
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix the EntityToJsonTransformer to return an empty array if the value is ""
|
* Fix the EntityToJsonTransformer to return an empty array if the value is ""
|
||||||
|
|
||||||
## v3.5.2 - 2024-12-19
|
## v3.5.2 - 2024-12-19
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#345](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/345)) Export: activity filtering of users that were associated to an activity between certain dates. Results contained activities that were not within the specified date range"
|
* ([#345](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/345)) Export: activity filtering of users that were associated to an activity between certain dates. Results contained activities that were not within the specified date range"
|
||||||
|
|
||||||
## v3.5.1 - 2024-12-16
|
## v3.5.1 - 2024-12-16
|
||||||
### Fixed
|
### Fixed
|
||||||
* Filiation: fix the display of the gender label in the graph
|
* Filiation: fix the display of the gender label in the graph
|
||||||
* Wrap handling of PdfSignedMessage into transactions
|
* Wrap handling of PdfSignedMessage into transactions
|
||||||
|
|
||||||
## v3.5.0 - 2024-12-09
|
## v3.5.0 - 2024-12-09
|
||||||
### Feature
|
### Feature
|
||||||
* ([#318](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/318)) Show all the pages of the documents in the signature app
|
* ([#318](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/318)) Show all the pages of the documents in the signature app
|
||||||
### Fixed
|
### Fixed
|
||||||
* Wrap the signature's change state into a transaction, to avoid race conditions
|
* Wrap the signature's change state into a transaction, to avoid race conditions
|
||||||
* Fix display of gender label
|
* Fix display of gender label
|
||||||
|
|
||||||
## v3.4.3 - 2024-12-05
|
## v3.4.3 - 2024-12-05
|
||||||
### Fixed
|
### Fixed
|
||||||
@@ -378,76 +397,76 @@ chill_main:
|
|||||||
|
|
||||||
## v3.4.2 - 2024-12-05
|
## v3.4.2 - 2024-12-05
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#329](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/329)) Fix the serialization of gender for the generation of documents
|
* ([#329](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/329)) Fix the serialization of gender for the generation of documents
|
||||||
* ([#337](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/337)) Enforce unique contraint on activity storedobject
|
* ([#337](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/337)) Enforce unique contraint on activity storedobject
|
||||||
### DX
|
### DX
|
||||||
* ([#310](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/310)) Clean migrations, to reduce the number of bloated migration when running diff on schema
|
* ([#310](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/310)) Clean migrations, to reduce the number of bloated migration when running diff on schema
|
||||||
|
|
||||||
## v3.4.1 - 2024-11-22
|
## v3.4.1 - 2024-11-22
|
||||||
### Fixed
|
### Fixed
|
||||||
* Set the workflow's title to notification content and subject
|
* Set the workflow's title to notification content and subject
|
||||||
|
|
||||||
## v3.4.0 - 2024-11-20
|
## v3.4.0 - 2024-11-20
|
||||||
### Feature
|
### Feature
|
||||||
* ([#314](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/314)) Admin: improve document type admin form with a select field for related class.
|
* ([#314](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/314)) Admin: improve document type admin form with a select field for related class.
|
||||||
Admin: Allow administrator to assign multiple group centers in one go to a user.
|
Admin: Allow administrator to assign multiple group centers in one go to a user.
|
||||||
|
|
||||||
## v3.3.0 - 2024-11-20
|
## v3.3.0 - 2024-11-20
|
||||||
### Feature
|
### Feature
|
||||||
* Electronic signature
|
* Electronic signature
|
||||||
|
|
||||||
Implementation of the electronic signature for documents within chill.
|
Implementation of the electronic signature for documents within chill.
|
||||||
* ([#286](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/286)) The behavoir of the voters for stored objects is adjusted so as to limit edit and delete possibilities to users related to the activity, social action or workflow entity.
|
* ([#286](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/286)) The behavoir of the voters for stored objects is adjusted so as to limit edit and delete possibilities to users related to the activity, social action or workflow entity.
|
||||||
* ([#288](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/288)) Metadata form added for person signatures
|
* ([#288](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/288)) Metadata form added for person signatures
|
||||||
* Add a signature step in workflow, which allow to apply an electronic signature on documents
|
* Add a signature step in workflow, which allow to apply an electronic signature on documents
|
||||||
* Keep an history of each version of a stored object.
|
* Keep an history of each version of a stored object.
|
||||||
* Add a "send external" step in workflow, which allow to send stored objects and other elements to remote people, by sending them a public url
|
* Add a "send external" step in workflow, which allow to send stored objects and other elements to remote people, by sending them a public url
|
||||||
### Fixed
|
### Fixed
|
||||||
* Adjust household list export to include households even if their address is NULL
|
* Adjust household list export to include households even if their address is NULL
|
||||||
* Remove validation of date string on deathDate
|
* Remove validation of date string on deathDate
|
||||||
|
|
||||||
## v3.2.4 - 2024-11-06
|
## v3.2.4 - 2024-11-06
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix compilation of chill assets
|
* Fix compilation of chill assets
|
||||||
|
|
||||||
## v3.2.3 - 2024-11-05
|
## v3.2.3 - 2024-11-05
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#315](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/315)) Fix display of accompanying period work referrers. Only current referrers should be displayed.
|
* ([#315](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/315)) Fix display of accompanying period work referrers. Only current referrers should be displayed.
|
||||||
Fix color of Chill footer
|
Fix color of Chill footer
|
||||||
|
|
||||||
## v3.2.2 - 2024-10-31
|
## v3.2.2 - 2024-10-31
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix gender translation for unknown
|
* Fix gender translation for unknown
|
||||||
|
|
||||||
## v3.2.1 - 2024-10-31
|
## v3.2.1 - 2024-10-31
|
||||||
### Fixed
|
### Fixed
|
||||||
* Add the possibility of unknown to the gender entity
|
* Add the possibility of unknown to the gender entity
|
||||||
* Fix the fusion of person doubles by excluding accompanyingPeriod work entities to be deleted. They are moved instead.
|
* Fix the fusion of person doubles by excluding accompanyingPeriod work entities to be deleted. They are moved instead.
|
||||||
|
|
||||||
## v3.2.0 - 2024-10-30
|
## v3.2.0 - 2024-10-30
|
||||||
### Feature
|
### Feature
|
||||||
* Introduce a gender entity
|
* Introduce a gender entity
|
||||||
|
|
||||||
## v3.1.1 - 2024-10-01
|
## v3.1.1 - 2024-10-01
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#308](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/308)) Show only the current referrer in the page "show" for an accompanying period workf
|
* ([#308](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/308)) Show only the current referrer in the page "show" for an accompanying period workf
|
||||||
* ([#309](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/309)) Correctly compute the grouping by referrer aggregator
|
* ([#309](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/309)) Correctly compute the grouping by referrer aggregator
|
||||||
|
|
||||||
* Fixed typing of custom field long choice and custom field group
|
* Fixed typing of custom field long choice and custom field group
|
||||||
|
|
||||||
## v3.1.0 - 2024-08-30
|
## v3.1.0 - 2024-08-30
|
||||||
### Feature
|
### Feature
|
||||||
* Add export aggregator to aggregate activities by household + filter persons that are not part of an accompanyingperiod during a certain timeframe.
|
* Add export aggregator to aggregate activities by household + filter persons that are not part of an accompanyingperiod during a certain timeframe.
|
||||||
|
|
||||||
## v3.0.0 - 2024-08-26
|
## v3.0.0 - 2024-08-26
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix delete action for accompanying periods in draft state
|
* Fix delete action for accompanying periods in draft state
|
||||||
* Fix connection to azure when making an calendar event in chill
|
* Fix connection to azure when making an calendar event in chill
|
||||||
* CollectionType js fixes for remove button and adding multiple entries
|
* CollectionType js fixes for remove button and adding multiple entries
|
||||||
|
|
||||||
## v2.24.0 - 2024-09-11
|
## v2.24.0 - 2024-09-11
|
||||||
### Feature
|
### Feature
|
||||||
* ([#306](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/306)) When a document is converted or downloaded in the browser, this document is removed from the browser memory after 45s. Future click on the button re-download the document.
|
* ([#306](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/306)) When a document is converted or downloaded in the browser, this document is removed from the browser memory after 45s. Future click on the button re-download the document.
|
||||||
|
|
||||||
## v2.23.0 - 2024-07-23 & 2024-07-19
|
## v2.23.0 - 2024-07-23 & 2024-07-19
|
||||||
### Feature
|
### Feature
|
||||||
@@ -482,13 +501,13 @@ Fix color of Chill footer
|
|||||||
|
|
||||||
## v2.22.2 - 2024-07-03
|
## v2.22.2 - 2024-07-03
|
||||||
### Fixed
|
### Fixed
|
||||||
* Remove scope required for event participation stats
|
* Remove scope required for event participation stats
|
||||||
|
|
||||||
## v2.22.1 - 2024-07-01
|
## v2.22.1 - 2024-07-01
|
||||||
### Fixed
|
### Fixed
|
||||||
* Remove debug word
|
* Remove debug word
|
||||||
### DX
|
### DX
|
||||||
* Add a command for reading official address DB from Luxembourg and update chill addresses
|
* Add a command for reading official address DB from Luxembourg and update chill addresses
|
||||||
|
|
||||||
## v2.22.0 - 2024-06-25
|
## v2.22.0 - 2024-06-25
|
||||||
### Feature
|
### Feature
|
||||||
@@ -531,7 +550,7 @@ Fix color of Chill footer
|
|||||||
|
|
||||||
## v2.20.1 - 2024-06-05
|
## v2.20.1 - 2024-06-05
|
||||||
### Fixed
|
### Fixed
|
||||||
* Do not allow StoredObjectCreated for edit and convert buttons
|
* Do not allow StoredObjectCreated for edit and convert buttons
|
||||||
|
|
||||||
## v2.20.0 - 2024-06-05
|
## v2.20.0 - 2024-06-05
|
||||||
### Fixed
|
### Fixed
|
||||||
@@ -578,96 +597,96 @@ Fix color of Chill footer
|
|||||||
|
|
||||||
## v2.18.2 - 2024-04-12
|
## v2.18.2 - 2024-04-12
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#250](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/250)) Postal codes import : fix the source URL and the keys to handle each record
|
* ([#250](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/250)) Postal codes import : fix the source URL and the keys to handle each record
|
||||||
|
|
||||||
## v2.18.1 - 2024-03-26
|
## v2.18.1 - 2024-03-26
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix layout issue in document generation for admin (minor)
|
* Fix layout issue in document generation for admin (minor)
|
||||||
|
|
||||||
## v2.18.0 - 2024-03-26
|
## v2.18.0 - 2024-03-26
|
||||||
### Feature
|
### Feature
|
||||||
* ([#268](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/268)) Improve admin UX to configure document templates for document generation
|
* ([#268](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/268)) Improve admin UX to configure document templates for document generation
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#267](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/267)) Fix the join between job and user in the user list (admin): show only the current user job
|
* ([#267](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/267)) Fix the join between job and user in the user list (admin): show only the current user job
|
||||||
|
|
||||||
## v2.17.0 - 2024-03-19
|
## v2.17.0 - 2024-03-19
|
||||||
### Feature
|
### Feature
|
||||||
* ([#237](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/237)) New export filter for social actions with an evaluation created between two dates
|
* ([#237](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/237)) New export filter for social actions with an evaluation created between two dates
|
||||||
* ([#258](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/258)) In the list of accompangying period, add the list of person's centers and the duration of the course
|
* ([#258](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/258)) In the list of accompangying period, add the list of person's centers and the duration of the course
|
||||||
* ([#238](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/238)) Allow to customize list person with new fields
|
* ([#238](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/238)) Allow to customize list person with new fields
|
||||||
* ([#159](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/159)) Admin can publish news on the homepage
|
* ([#159](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/159)) Admin can publish news on the homepage
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#264](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/264)) Fix languages: load the languages in all availables languages configured for Chill
|
* ([#264](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/264)) Fix languages: load the languages in all availables languages configured for Chill
|
||||||
* ([#259](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/259)) Keep a consistent behaviour between the filtering of activities within the document generation (model "accompanying period with activities"), and the same filter in the list of activities for an accompanying period
|
* ([#259](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/259)) Keep a consistent behaviour between the filtering of activities within the document generation (model "accompanying period with activities"), and the same filter in the list of activities for an accompanying period
|
||||||
|
|
||||||
## v2.16.3 - 2024-02-26
|
## v2.16.3 - 2024-02-26
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#236](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/236)) Fix translation of user job -> 'service' must be 'métier'
|
* ([#236](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/236)) Fix translation of user job -> 'service' must be 'métier'
|
||||||
### UX
|
### UX
|
||||||
* ([#232](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/232)) Order user jobs and services alphabetically in export filters
|
* ([#232](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/232)) Order user jobs and services alphabetically in export filters
|
||||||
|
|
||||||
## v2.16.2 - 2024-02-21
|
## v2.16.2 - 2024-02-21
|
||||||
### Fixed
|
### Fixed
|
||||||
* Check for null values in closing motive of parcours d'accompagnement for correct rendering of template
|
* Check for null values in closing motive of parcours d'accompagnement for correct rendering of template
|
||||||
|
|
||||||
## v2.16.1 - 2024-02-09
|
## v2.16.1 - 2024-02-09
|
||||||
### Fixed
|
### Fixed
|
||||||
* Force bootstrap version to avoid error in builds with newer version
|
* Force bootstrap version to avoid error in builds with newer version
|
||||||
|
|
||||||
## v2.16.0 - 2024-02-08
|
## v2.16.0 - 2024-02-08
|
||||||
### Feature
|
### Feature
|
||||||
* ([#231](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/231)) Create new filter for persons having a participation in an accompanying period during a certain time span
|
* ([#231](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/231)) Create new filter for persons having a participation in an accompanying period during a certain time span
|
||||||
* ([#241](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/241)) [Export][List of accompanyign period] Add two columns: the list of persons participating to the period, and their ids
|
* ([#241](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/241)) [Export][List of accompanyign period] Add two columns: the list of persons participating to the period, and their ids
|
||||||
* ([#244](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/244)) Add capability to generate export about change of steps of accompanying period, and generate exports for this
|
* ([#244](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/244)) Add capability to generate export about change of steps of accompanying period, and generate exports for this
|
||||||
* ([#253](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/253)) Export: group accompanying period by person participating
|
* ([#253](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/253)) Export: group accompanying period by person participating
|
||||||
* ([#243](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/243)) Export: add filter for courses not linked to a reference address
|
* ([#243](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/243)) Export: add filter for courses not linked to a reference address
|
||||||
* ([#229](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/229)) Allow to group activities linked with accompanying period by reason
|
* ([#229](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/229)) Allow to group activities linked with accompanying period by reason
|
||||||
* ([#115](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/115)) Prevent social work to be saved when another user edited conccurently the social work
|
* ([#115](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/115)) Prevent social work to be saved when another user edited conccurently the social work
|
||||||
* Modernize the event bundle, with some new fields and multiple improvements
|
* Modernize the event bundle, with some new fields and multiple improvements
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#220](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/220)) Fix error in logs about wrong typing of eventArgs in onEditNotificationComment method
|
* ([#220](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/220)) Fix error in logs about wrong typing of eventArgs in onEditNotificationComment method
|
||||||
* ([#256](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/256)) Fix the conditions upon which social actions should be optional or required in relation to social issues within the activity creation form
|
* ([#256](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/256)) Fix the conditions upon which social actions should be optional or required in relation to social issues within the activity creation form
|
||||||
### UX
|
### UX
|
||||||
* ([#260](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/260)) Order list of centers alphabetically in dropdown 'user' section admin.
|
* ([#260](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/260)) Order list of centers alphabetically in dropdown 'user' section admin.
|
||||||
|
|
||||||
## v2.15.2 - 2024-01-11
|
## v2.15.2 - 2024-01-11
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix the id_seq used when creating a new accompanying period participation during fusion of two person files
|
* Fix the id_seq used when creating a new accompanying period participation during fusion of two person files
|
||||||
### DX
|
### DX
|
||||||
* Set placeholder to False for expanded EntityType form fields where required is set to False.
|
* Set placeholder to False for expanded EntityType form fields where required is set to False.
|
||||||
|
|
||||||
## v2.15.1 - 2023-12-20
|
## v2.15.1 - 2023-12-20
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix the household export query to exclude accompanying periods that are in draft state.
|
* Fix the household export query to exclude accompanying periods that are in draft state.
|
||||||
### DX
|
### DX
|
||||||
* ([#167](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/167)) Fixed readthedocs compilation by updating readthedocs config file and requirements for Sphinx
|
* ([#167](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/167)) Fixed readthedocs compilation by updating readthedocs config file and requirements for Sphinx
|
||||||
|
|
||||||
## v2.15.0 - 2023-12-11
|
## v2.15.0 - 2023-12-11
|
||||||
### Feature
|
### Feature
|
||||||
* ([#191](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/191)) Add export "number of household associate with an exchange"
|
* ([#191](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/191)) Add export "number of household associate with an exchange"
|
||||||
* ([#235](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/235)) Export: add dates on the filter "filter course by activity type"
|
* ([#235](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/235)) Export: add dates on the filter "filter course by activity type"
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#214](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/214)) Fix error when posting an empty comment on an accompanying period.
|
* ([#214](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/214)) Fix error when posting an empty comment on an accompanying period.
|
||||||
* ([#233](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/233)) Fix "filter evaluation by evaluation type" (and add select2 to the list of evaluation types to pick)
|
* ([#233](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/233)) Fix "filter evaluation by evaluation type" (and add select2 to the list of evaluation types to pick)
|
||||||
* ([#234](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/234)) Fix "filter aside activity by date"
|
* ([#234](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/234)) Fix "filter aside activity by date"
|
||||||
|
|
||||||
* ([#228](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/228)) Fix export of activity for people created before the introduction of the createdAt column on person (during v1)
|
* ([#228](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/228)) Fix export of activity for people created before the introduction of the createdAt column on person (during v1)
|
||||||
* ([#246](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/246)) Do not show activities, evaluations and social work when associated to a confidential accompanying period, except for the users which are allowed to see them
|
* ([#246](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/246)) Do not show activities, evaluations and social work when associated to a confidential accompanying period, except for the users which are allowed to see them
|
||||||
|
|
||||||
## v2.14.1 - 2023-11-29
|
## v2.14.1 - 2023-11-29
|
||||||
### Fixed
|
### Fixed
|
||||||
* Export: fix list person with custom fields
|
* Export: fix list person with custom fields
|
||||||
* ([#100](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/100)) Add a paginator to budget elements (resource and charge types) in the admin
|
* ([#100](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/100)) Add a paginator to budget elements (resource and charge types) in the admin
|
||||||
* Fix error in ListEvaluation when "handling agents" are alone
|
* Fix error in ListEvaluation when "handling agents" are alone
|
||||||
|
|
||||||
## v2.14.0 - 2023-11-24
|
## v2.14.0 - 2023-11-24
|
||||||
### Feature
|
### Feature
|
||||||
* ([#161](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/161)) Export: in filter "Filter accompanying period work (social action) by type, goal and result", order the items alphabetically or with the defined order
|
* ([#161](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/161)) Export: in filter "Filter accompanying period work (social action) by type, goal and result", order the items alphabetically or with the defined order
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#141](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/141)) Export: on filter "action by type goals, and results", restore the fields when editing a saved export
|
* ([#141](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/141)) Export: on filter "action by type goals, and results", restore the fields when editing a saved export
|
||||||
* ([#219](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/219)) Export: fix the list of accompanying period work, when the "calc date" is null
|
* ([#219](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/219)) Export: fix the list of accompanying period work, when the "calc date" is null
|
||||||
* ([#222](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/222)) Fix rendering of custom fields
|
* ([#222](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/222)) Fix rendering of custom fields
|
||||||
* Fix various errors in custom fields administration
|
* Fix various errors in custom fields administration
|
||||||
|
|
||||||
## v2.13.0 - 2023-11-21
|
## v2.13.0 - 2023-11-21
|
||||||
### Feature
|
### Feature
|
||||||
@@ -681,7 +700,7 @@ Fix color of Chill footer
|
|||||||
|
|
||||||
## v2.12.1 - 2023-11-16
|
## v2.12.1 - 2023-11-16
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#208](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/208)) Export: fix loading of form for "filter action by type, goal and result"
|
* ([#208](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/208)) Export: fix loading of form for "filter action by type, goal and result"
|
||||||
|
|
||||||
## v2.12.0 - 2023-11-15
|
## v2.12.0 - 2023-11-15
|
||||||
### Feature
|
### Feature
|
||||||
@@ -712,36 +731,36 @@ Fix color of Chill footer
|
|||||||
|
|
||||||
## v2.11.0 - 2023-11-07
|
## v2.11.0 - 2023-11-07
|
||||||
### Feature
|
### Feature
|
||||||
* ([#194](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/194)) Export: add a filter "filter activity by creator job"
|
* ([#194](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/194)) Export: add a filter "filter activity by creator job"
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#185](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/185)) Export: fix "group accompanying period by geographical unit": take into account the accompanying periods when the period is not located within an unit
|
* ([#185](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/185)) Export: fix "group accompanying period by geographical unit": take into account the accompanying periods when the period is not located within an unit
|
||||||
* Fix "group activity by creator job" aggregator
|
* Fix "group activity by creator job" aggregator
|
||||||
|
|
||||||
## v2.10.6 - 2023-11-07
|
## v2.10.6 - 2023-11-07
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#182](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/182)) Fix merging of double person files. Adjustement relationship sql statement
|
* ([#182](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/182)) Fix merging of double person files. Adjustement relationship sql statement
|
||||||
* ([#185](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/185)) Export: fix aggregator by geographical unit on person: avoid inconsistencies
|
* ([#185](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/185)) Export: fix aggregator by geographical unit on person: avoid inconsistencies
|
||||||
|
|
||||||
## v2.10.5 - 2023-11-05
|
## v2.10.5 - 2023-11-05
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#183](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/183)) Fix "problem during download" on some filters, which used a wrong data type
|
* ([#183](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/183)) Fix "problem during download" on some filters, which used a wrong data type
|
||||||
* ([#184](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/184)) Fix filter "activity by date"
|
* ([#184](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/184)) Fix filter "activity by date"
|
||||||
|
|
||||||
## v2.10.4 - 2023-10-26
|
## v2.10.4 - 2023-10-26
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix null value constraint errors when merging relationships in doubles
|
* Fix null value constraint errors when merging relationships in doubles
|
||||||
|
|
||||||
## v2.10.3 - 2023-10-26
|
## v2.10.3 - 2023-10-26
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#175](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/175)) Replace old method of getting translator with injection of translatorInterface
|
* ([#175](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/175)) Replace old method of getting translator with injection of translatorInterface
|
||||||
|
|
||||||
## v2.10.2 - 2023-10-26
|
## v2.10.2 - 2023-10-26
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#175](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/175)) Use injection of translator instead of ->get().
|
* ([#175](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/175)) Use injection of translator instead of ->get().
|
||||||
|
|
||||||
## v2.10.1 - 2023-10-24
|
## v2.10.1 - 2023-10-24
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix export controller when generating an export without any data in session
|
* Fix export controller when generating an export without any data in session
|
||||||
|
|
||||||
## v2.10.0 - 2023-10-24
|
## v2.10.0 - 2023-10-24
|
||||||
### Feature
|
### Feature
|
||||||
@@ -761,16 +780,16 @@ Fix color of Chill footer
|
|||||||
- ajout d'un filtre et regroupement par usager participant sur les échanges
|
- ajout d'un filtre et regroupement par usager participant sur les échanges
|
||||||
- ajout d'un regroupement: par type d'activité associé au parcours;
|
- ajout d'un regroupement: par type d'activité associé au parcours;
|
||||||
- trie les filtre et regroupements par ordre alphabétique dans els exports
|
- trie les filtre et regroupements par ordre alphabétique dans els exports
|
||||||
- ajout d'un paramètre qui permet de désactiver le filtre par centre dans les exports
|
- ajout d'un paramètre qui permet de désactiver le filtre par territoire dans les exports
|
||||||
- correction de l'interface de date dans les filtres et regroupements "par statut du parcours à la date"
|
- correction de l'interface de date dans les filtres et regroupements "par statut du parcours à la date"
|
||||||
|
|
||||||
## v2.9.2 - 2023-10-17
|
## v2.9.2 - 2023-10-17
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix possible null values in string's entities
|
* Fix possible null values in string's entities
|
||||||
|
|
||||||
## v2.9.1 - 2023-10-17
|
## v2.9.1 - 2023-10-17
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix the handling of activity form when editing or creating an activity in an accompanying period with multiple centers
|
* Fix the handling of activity form when editing or creating an activity in an accompanying period with multiple centers
|
||||||
|
|
||||||
## v2.9.0 - 2023-10-17
|
## v2.9.0 - 2023-10-17
|
||||||
### Feature
|
### Feature
|
||||||
@@ -818,57 +837,57 @@ But if you do not need this any more, you must ensure that the configuration key
|
|||||||
|
|
||||||
## v2.7.0 - 2023-09-27
|
## v2.7.0 - 2023-09-27
|
||||||
### Feature
|
### Feature
|
||||||
* ([#155](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/155)) The regulation list load accompanying periods by exact postal code (address associated with postal code), and not by the content of the postal code (postal code with same code's string)
|
* ([#155](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/155)) The regulation list load accompanying periods by exact postal code (address associated with postal code), and not by the content of the postal code (postal code with same code's string)
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#142](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/142)) Fix the label of filter ActivityTypeFilter to a more obvious one
|
* ([#142](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/142)) Fix the label of filter ActivityTypeFilter to a more obvious one
|
||||||
* ([#140](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/140)) [export] Fix association of filter "filter location by type" which did not appears on "list of activities"
|
* ([#140](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/140)) [export] Fix association of filter "filter location by type" which did not appears on "list of activities"
|
||||||
|
|
||||||
## v2.6.3 - 2023-09-19
|
## v2.6.3 - 2023-09-19
|
||||||
### Fixed
|
### Fixed
|
||||||
* Remove id property from document
|
* Remove id property from document
|
||||||
mappedsuperclass
|
mappedsuperclass
|
||||||
|
|
||||||
## v2.6.2 - 2023-09-18
|
## v2.6.2 - 2023-09-18
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix doctrine mapping of AbstractTaskPlaceEvent and SingleTaskPlaceEvent: id property moved.
|
* Fix doctrine mapping of AbstractTaskPlaceEvent and SingleTaskPlaceEvent: id property moved.
|
||||||
|
|
||||||
## v2.6.1 - 2023-09-14
|
## v2.6.1 - 2023-09-14
|
||||||
### Fixed
|
### Fixed
|
||||||
* Filter out active centers in exports, which uses a different PickCenterType.
|
* Filter out active centers in exports, which uses a different PickCenterType.
|
||||||
|
|
||||||
## v2.6.0 - 2023-09-14
|
## v2.6.0 - 2023-09-14
|
||||||
### Feature
|
### Feature
|
||||||
* ([#133](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/133)) Add locations in Aside Activity. By default, suggest user location, otherwise a select with all locations.
|
* ([#133](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/133)) Add locations in Aside Activity. By default, suggest user location, otherwise a select with all locations.
|
||||||
* ([#133](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/133)) Adapt Aside Activity exports: display location, filter by location, group by location
|
* ([#133](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/133)) Adapt Aside Activity exports: display location, filter by location, group by location
|
||||||
* Use the CRUD controller for center entity + add the isActive property to be able to mask instances of Center that are no longer in use.
|
* Use the CRUD controller for center entity + add the isActive property to be able to mask instances of Center that are no longer in use.
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#107](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/107)) reinstate the fusion of duplicate persons
|
* ([#107](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/107)) reinstate the fusion of duplicate persons
|
||||||
* Missing translation in Work Actions exports
|
* Missing translation in Work Actions exports
|
||||||
* Reimplement the mission type filter on tasks, only for instances that have a config parameter indicating true for this.
|
* Reimplement the mission type filter on tasks, only for instances that have a config parameter indicating true for this.
|
||||||
* ([#135](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/135)) Corrects a typing error in 2 filters, which caused an
|
* ([#135](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/135)) Corrects a typing error in 2 filters, which caused an
|
||||||
error when trying to reedit a saved export
|
error when trying to reedit a saved export
|
||||||
|
|
||||||
|
|
||||||
* ([#136](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/136)) [household] when moving a person to a sharing position to a not-sharing position on the same household on the same date, remove the previous household membership on the same household. This fix duplicate member.
|
* ([#136](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/136)) [household] when moving a person to a sharing position to a not-sharing position on the same household on the same date, remove the previous household membership on the same household. This fix duplicate member.
|
||||||
* Add missing translation for comment field placeholder in repositionning household editor.
|
* Add missing translation for comment field placeholder in repositionning household editor.
|
||||||
|
|
||||||
* Do not send an email to creator twice when adding a comment to a notification
|
* Do not send an email to creator twice when adding a comment to a notification
|
||||||
* ([#107](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/107)) Fix gestion doublon functionality to work with chill bundles v2
|
* ([#107](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/107)) Fix gestion doublon functionality to work with chill bundles v2
|
||||||
### UX
|
### UX
|
||||||
* Uniformize badge-person in household banner (background, size)
|
* Uniformize badge-person in household banner (background, size)
|
||||||
|
|
||||||
|
|
||||||
## v2.5.3 - 2023-07-20
|
## v2.5.3 - 2023-07-20
|
||||||
### Fixed
|
### Fixed
|
||||||
* ([#132](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/132)) Rendez-vous documents created would appear in all documents lists of all persons with an accompanying period. Or statements are now added to the where clause to filter out documents that come from unrelated accompanying period/ or person rendez-vous.
|
* ([#132](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/132)) Rendez-vous documents created would appear in all documents lists of all persons with an accompanying period. Or statements are now added to the where clause to filter out documents that come from unrelated accompanying period/ or person rendez-vous.
|
||||||
|
|
||||||
## v2.5.2 - 2023-07-15
|
## v2.5.2 - 2023-07-15
|
||||||
### Fixed
|
### Fixed
|
||||||
* [Collate Address] when updating address point, do not use the point's address reference if the similarity is below the requirement for associating the address reference and the address (it uses the postcode's center instead)
|
* [Collate Address] when updating address point, do not use the point's address reference if the similarity is below the requirement for associating the address reference and the address (it uses the postcode's center instead)
|
||||||
|
|
||||||
## v2.5.1 - 2023-07-14
|
## v2.5.1 - 2023-07-14
|
||||||
### Fixed
|
### Fixed
|
||||||
* [collate addresses] block collating addresses to another address reference where the address reference is already the best match
|
* [collate addresses] block collating addresses to another address reference where the address reference is already the best match
|
||||||
|
|
||||||
## v2.5.0 - 2023-07-14
|
## v2.5.0 - 2023-07-14
|
||||||
### Feature
|
### Feature
|
||||||
@@ -941,7 +960,7 @@ error when trying to reedit a saved export
|
|||||||
- ajout d'un regroupement par métier des intervenants sur un parcours;
|
- ajout d'un regroupement par métier des intervenants sur un parcours;
|
||||||
- ajout d'un regroupement par service des intervenants sur un parcours;
|
- ajout d'un regroupement par service des intervenants sur un parcours;
|
||||||
- ajout d'un regroupement par utilisateur intervenant sur un parcours
|
- ajout d'un regroupement par utilisateur intervenant sur un parcours
|
||||||
- ajout d'un regroupement "par centre de l'usager";
|
- ajout d'un regroupement "par territoire de l'usager";
|
||||||
- ajout d'un filtre "par métier intervenant sur un parcours";
|
- ajout d'un filtre "par métier intervenant sur un parcours";
|
||||||
- ajout d'un filtre "par service intervenant sur un parcours";
|
- ajout d'un filtre "par service intervenant sur un parcours";
|
||||||
- création d'un rôle spécifique pour voir les parcours confidentiels (et séparer de celui de la liste qui permet de ré-assigner les parcours en lot);
|
- création d'un rôle spécifique pour voir les parcours confidentiels (et séparer de celui de la liste qui permet de ré-assigner les parcours en lot);
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ Arborescence:
|
|||||||
- person
|
- person
|
||||||
- personvendee
|
- personvendee
|
||||||
- household_edit_metadata
|
- household_edit_metadata
|
||||||
- index.js
|
- index.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
## Organisation des feuilles de styles
|
## Organisation des feuilles de styles
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import { trans, setLocale, setLocaleFallbacks } from "./ux-translator";
|
import {
|
||||||
|
trans,
|
||||||
|
setLocale,
|
||||||
|
getLocale,
|
||||||
|
setLocaleFallbacks,
|
||||||
|
} from "./ux-translator";
|
||||||
|
|
||||||
setLocaleFallbacks({"en": "fr", "nl": "fr", "fr": "en"});
|
setLocaleFallbacks({ en: "fr", nl: "fr", fr: "en" });
|
||||||
setLocale('fr');
|
setLocale("fr");
|
||||||
|
|
||||||
export { trans };
|
export { trans, getLocale };
|
||||||
export * from '../var/translations';
|
export * from "../var/translations";
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"ext-openssl": "*",
|
"ext-openssl": "*",
|
||||||
"ext-redis": "*",
|
"ext-redis": "*",
|
||||||
"ext-zlib": "*",
|
"ext-zlib": "*",
|
||||||
"champs-libres/wopi-bundle": "dev-master@dev",
|
"champs-libres/wopi-bundle": "dev-symfony-v5@dev",
|
||||||
"champs-libres/wopi-lib": "dev-master@dev",
|
"champs-libres/wopi-lib": "dev-master@dev",
|
||||||
"doctrine/data-fixtures": "^1.8",
|
"doctrine/data-fixtures": "^1.8",
|
||||||
"doctrine/doctrine-bundle": "^2.1",
|
"doctrine/doctrine-bundle": "^2.1",
|
||||||
@@ -133,6 +133,7 @@
|
|||||||
"Chill\\TaskBundle\\": "src/Bundle/ChillTaskBundle",
|
"Chill\\TaskBundle\\": "src/Bundle/ChillTaskBundle",
|
||||||
"Chill\\ThirdPartyBundle\\": "src/Bundle/ChillThirdPartyBundle",
|
"Chill\\ThirdPartyBundle\\": "src/Bundle/ChillThirdPartyBundle",
|
||||||
"Chill\\WopiBundle\\": "src/Bundle/ChillWopiBundle/src",
|
"Chill\\WopiBundle\\": "src/Bundle/ChillWopiBundle/src",
|
||||||
|
"Chill\\TicketBundle\\": "src/Bundle/ChillTicketBundle/src",
|
||||||
"Chill\\Utils\\Rector\\": "utils/rector/src"
|
"Chill\\Utils\\Rector\\": "utils/rector/src"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
||||||
loophp\PsrHttpMessageBridgeBundle\PsrHttpMessageBridgeBundle::class => ['all' => true],
|
|
||||||
ChampsLibres\WopiBundle\WopiBundle::class => ['all' => true],
|
ChampsLibres\WopiBundle\WopiBundle::class => ['all' => true],
|
||||||
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
|
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
|
||||||
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
|
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
|
||||||
@@ -35,6 +34,8 @@ return [
|
|||||||
Chill\ThirdPartyBundle\ChillThirdPartyBundle::class => ['all' => true],
|
Chill\ThirdPartyBundle\ChillThirdPartyBundle::class => ['all' => true],
|
||||||
Chill\BudgetBundle\ChillBudgetBundle::class => ['all' => true],
|
Chill\BudgetBundle\ChillBudgetBundle::class => ['all' => true],
|
||||||
Chill\WopiBundle\ChillWopiBundle::class => ['all' => true],
|
Chill\WopiBundle\ChillWopiBundle::class => ['all' => true],
|
||||||
|
Chill\TicketBundle\ChillTicketBundle::class => ['all' => true],
|
||||||
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
|
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
|
||||||
Symfony\UX\Translator\UxTranslatorBundle::class => ['all' => true],
|
Symfony\UX\Translator\UxTranslatorBundle::class => ['all' => true],
|
||||||
|
loophp\PsrHttpMessageBridgeBundle\PsrHttpMessageBridgeBundle::class => ['all' => true],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
chill_main:
|
chill_main:
|
||||||
available_languages: [ '%env(resolve:LOCALE)%', 'en' ]
|
available_languages: [ '%env(resolve:LOCALE)%', 'en' ]
|
||||||
available_countries: ['BE', 'FR']
|
available_countries: ['BE', 'FR']
|
||||||
|
top_banner:
|
||||||
|
visible: false
|
||||||
|
text:
|
||||||
|
fr: 'Vous travaillez actuellement avec la version de PRÉ-PRODUCTION.'
|
||||||
|
nl: 'Je werkt momenteel in de PRE-PRODUCTIE versie'
|
||||||
|
color: '#353535'
|
||||||
|
background_color: '#d8bb48'
|
||||||
notifications:
|
notifications:
|
||||||
from_email: '%env(resolve:NOTIFICATION_FROM_EMAIL)%'
|
from_email: '%env(resolve:NOTIFICATION_FROM_EMAIL)%'
|
||||||
from_name: '%env(resolve:NOTIFICATION_FROM_NAME)%'
|
from_name: '%env(resolve:NOTIFICATION_FROM_NAME)%'
|
||||||
|
|||||||
2
config/packages/chill_aside_activity.yaml
Normal file
2
config/packages/chill_aside_activity.yaml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
chill_aside_activity:
|
||||||
|
show_concerned_persons_count: hidden
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
chill_doc_store:
|
chill_doc_store:
|
||||||
use_driver: openstack
|
use_driver: local_storage
|
||||||
local_storage:
|
local_storage:
|
||||||
storage_path: '%kernel.project_dir%/var/storage'
|
storage_path: '%kernel.project_dir%/var/storage'
|
||||||
openstack:
|
openstack:
|
||||||
|
|||||||
5
config/packages/chill_ticket.yaml
Normal file
5
config/packages/chill_ticket.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
chill_ticket:
|
||||||
|
ticket:
|
||||||
|
person_per_ticket: one # One of "one"; "many"
|
||||||
|
response_time_exceeded_delay: PT12H
|
||||||
|
|
||||||
@@ -14,6 +14,7 @@ doctrine_migrations:
|
|||||||
'Chill\Migrations\Calendar': '@ChillCalendarBundle/migrations'
|
'Chill\Migrations\Calendar': '@ChillCalendarBundle/migrations'
|
||||||
'Chill\Migrations\Budget': '@ChillBudgetBundle/migrations'
|
'Chill\Migrations\Budget': '@ChillBudgetBundle/migrations'
|
||||||
'Chill\Migrations\Report': '@ChillReportBundle/migrations'
|
'Chill\Migrations\Report': '@ChillReportBundle/migrations'
|
||||||
|
'Chill\Migrations\Ticket': '@ChillTicketBundle/migrations'
|
||||||
all_or_nothing:
|
all_or_nothing:
|
||||||
true
|
true
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ framework:
|
|||||||
'Chill\MainBundle\Export\Messenger\ExportRequestGenerationMessage': priority
|
'Chill\MainBundle\Export\Messenger\ExportRequestGenerationMessage': priority
|
||||||
'Chill\MainBundle\Export\Messenger\RemoveExportGenerationMessage': async
|
'Chill\MainBundle\Export\Messenger\RemoveExportGenerationMessage': async
|
||||||
'Chill\MainBundle\Notification\Email\NotificationEmailMessages\ScheduleDailyNotificationDigestMessage': async
|
'Chill\MainBundle\Notification\Email\NotificationEmailMessages\ScheduleDailyNotificationDigestMessage': async
|
||||||
|
'Chill\TicketBundle\Messenger\PostTicketUpdateMessage': async
|
||||||
# end of routes added by chill-bundles recipes
|
# end of routes added by chill-bundles recipes
|
||||||
# Route your messages to the transports
|
# Route your messages to the transports
|
||||||
# 'App\Message\YourMessage': async
|
# 'App\Message\YourMessage': async
|
||||||
|
|||||||
2
config/routes/chill_ticket.yaml
Normal file
2
config/routes/chill_ticket.yaml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
chill_ticket_bundle:
|
||||||
|
resource: '@ChillTicketBundle/config/routes.yaml'
|
||||||
@@ -23,8 +23,8 @@ class "Document" {
|
|||||||
- text description
|
- text description
|
||||||
- ArrayCollection_DocumentCategory categories
|
- ArrayCollection_DocumentCategory categories
|
||||||
- varchar_150 content #link to openstack
|
- varchar_150 content #link to openstack
|
||||||
- Center center
|
- Territoire territoire
|
||||||
- Cercle cercle
|
- Service service
|
||||||
- User user
|
- User user
|
||||||
- DateTime date # Creation date
|
- DateTime date # Creation date
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,24 +11,94 @@
|
|||||||
Create a new bundle
|
Create a new bundle
|
||||||
*******************
|
*******************
|
||||||
|
|
||||||
Create your own bundle is not a trivial task.
|
|
||||||
|
|
||||||
The easiest way to achieve this is seems to be :
|
|
||||||
|
|
||||||
1. Prepare a fresh installation of the chill project, in a new directory
|
|
||||||
2. Create a new bundle in this project, in the src directory
|
|
||||||
3. Initialize a git repository **at the root bundle**, and create your initial commit.
|
|
||||||
4. Register the bundle with composer/packagist. If you do not plan to distribute your bundle with packagist, you may use a custom repository for achieve this [#f1]_
|
|
||||||
5. Move to a development installation, made as described in the :ref:`installation-for-development` section, and add your new repository to the composer.json file
|
|
||||||
6. Work as :ref:`usual <editing-code-and-commiting>`
|
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
This part of the doc is not yet tested
|
This part of the doc is not yet tested
|
||||||
|
|
||||||
TODO
|
Create a new directory with Bundle class
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
mkdir -p src/Bundle/ChillSomeBundle/src/config
|
||||||
|
mkdir -p src/Bundle/ChillSomeBundle/src/Controller
|
||||||
|
|
||||||
|
Add a bundle file
|
||||||
|
|
||||||
|
.. code-block:: php
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\SomeBundle;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||||
|
|
||||||
|
class ChillSomeBundle extends Bundle {}
|
||||||
|
|
||||||
|
And a route file:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
chill_ticket_controller:
|
||||||
|
resource: '@ChillTicketBundle/Controller/'
|
||||||
|
type: annotation
|
||||||
|
|
||||||
|
Register the new psr-4 namespace
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
In composer.json, add the new psr4 namespace
|
||||||
|
|
||||||
|
.. code-block:: diff
|
||||||
|
|
||||||
|
{
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
+ "Chill\\SomeBundle\\": "src/Bundle/ChillSomeBundle/src",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.. rubric:: Footnotes
|
Register the bundle
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Register in the file :code:`config/bundles.php`:
|
||||||
|
|
||||||
|
.. code-block:: php
|
||||||
|
|
||||||
|
Vendor\Bundle\YourBundle\YourBundle::class => ['all' => true],
|
||||||
|
|
||||||
|
And import routes in :code:`config/routes/chill_some_bundle.yaml`:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
chill_ticket_bundle:
|
||||||
|
resource: '@ChillSomeBundle/config/routes.yaml'
|
||||||
|
|
||||||
|
Add the doctrine_migration namespace
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
Add the namespace to :code:`config/packages/doctrine_migrations_chill.yaml`
|
||||||
|
|
||||||
|
.. code-block:: diff
|
||||||
|
|
||||||
|
doctrine_migrations:
|
||||||
|
migrations_paths:
|
||||||
|
+ 'Chill\Some\Ticket': '@ChillSomeBundle/migrations'
|
||||||
|
|
||||||
|
Dump autoloading
|
||||||
|
----------------
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
symfony composer dump-autoload
|
||||||
|
|
||||||
.. [#f1] Be aware that we use the Affero GPL Licence, which ensure that all users must have access to derivative works done with this software.
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ Certaines données sont historisées:
|
|||||||
|
|
||||||
- les référents d'un parcours;
|
- les référents d'un parcours;
|
||||||
- les statuts d'un parcours;
|
- les statuts d'un parcours;
|
||||||
- la liaison entre les centres et les usagers;
|
- la liaison entre les territoires et les usagers;
|
||||||
- etc.
|
- etc.
|
||||||
|
|
||||||
Dans ces cas-là, Chill crée généralement deux colonnes, qui sont habituellement nommées :code:`startDate` et :code:`endDate`. Lorsque la colonne :code:`endDate` est à :code:`NULL`, cela signifie que la période n'est pas "fermée". La colonne :code:`startDate` n'est pas nullable.
|
Dans ces cas-là, Chill crée généralement deux colonnes, qui sont habituellement nommées :code:`startDate` et :code:`endDate`. Lorsque la colonne :code:`endDate` est à :code:`NULL`, cela signifie que la période n'est pas "fermée". La colonne :code:`startDate` n'est pas nullable.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
order,table_schema,table_name,commentaire
|
order,table_schema,table_name,commentaire
|
||||||
1,chill_3party,party_category,Catégorie de tiers
|
1,chill_3party,party_category,Catégorie de tiers
|
||||||
2,chill_3party,party_center,Association entre les tiers et les centres (déprécié)
|
2,chill_3party,party_center,Association entre les tiers et les territoires (déprécié)
|
||||||
3,chill_3party,party_profession,Profession du tiers (déprécié)
|
3,chill_3party,party_profession,Profession du tiers (déprécié)
|
||||||
4,chill_3party,third_party,Tiers
|
4,chill_3party,third_party,Tiers
|
||||||
5,chill_3party,thirdparty_category,association tiers - catégories
|
5,chill_3party,thirdparty_category,association tiers - catégories
|
||||||
@@ -54,7 +54,7 @@ order,table_schema,table_name,commentaire
|
|||||||
53,public,activitytpresence,Présence aux échanges
|
53,public,activitytpresence,Présence aux échanges
|
||||||
54,public,activitytype,Types d'échanges
|
54,public,activitytype,Types d'échanges
|
||||||
55,public,activitytypecategory,Catégories de types d'échanges
|
55,public,activitytypecategory,Catégories de types d'échanges
|
||||||
56,public,centers,"Centres (territoires, agences, etc.)"
|
56,public,centers,"Territoires (territoires, agences, etc.)"
|
||||||
57,public,chill_activity_activity_chill_person_socialaction,
|
57,public,chill_activity_activity_chill_person_socialaction,
|
||||||
58,public,chill_activity_activity_chill_person_socialissue
|
58,public,chill_activity_activity_chill_person_socialissue
|
||||||
59,public,chill_docgen_template,Gabarits de documents
|
59,public,chill_docgen_template,Gabarits de documents
|
||||||
@@ -111,7 +111,7 @@ order,table_schema,table_name,commentaire
|
|||||||
110,public,chill_person_marital_status,Etats civils
|
110,public,chill_person_marital_status,Etats civils
|
||||||
111,public,chill_person_not_duplicate,
|
111,public,chill_person_not_duplicate,
|
||||||
112,public,chill_person_person,Usagers
|
112,public,chill_person_person,Usagers
|
||||||
113,public,chill_person_person_center_history,Historique des centres d'un usagers
|
113,public,chill_person_person_center_history,Historique des territoires d'un usagers
|
||||||
114,public,chill_person_persons_to_addresses,Déprécié
|
114,public,chill_person_persons_to_addresses,Déprécié
|
||||||
115,public,chill_person_phone,Numéros d etéléphone supplémentaires d'un usager
|
115,public,chill_person_phone,Numéros d etéléphone supplémentaires d'un usager
|
||||||
116,public,chill_person_relations,Types de relations de filiation
|
116,public,chill_person_relations,Types de relations de filiation
|
||||||
@@ -142,7 +142,7 @@ order,table_schema,table_name,commentaire
|
|||||||
141,public,permission_groups
|
141,public,permission_groups
|
||||||
142,public,permissionsgroup_rolescope
|
142,public,permissionsgroup_rolescope
|
||||||
143,public,persons_spoken_languages
|
143,public,persons_spoken_languages
|
||||||
144,public,regroupment,Regroupement de centres
|
144,public,regroupment,Regroupement de territoires
|
||||||
145,public,regroupment_center,
|
145,public,regroupment_center,
|
||||||
146,public,role_scopes,
|
146,public,role_scopes,
|
||||||
147,public,scopes,Services
|
147,public,scopes,Services
|
||||||
|
|||||||
|
Can't render this file because it has a wrong number of fields in line 28.
|
@@ -41,6 +41,7 @@
|
|||||||
"typescript": "^5.6.3",
|
"typescript": "^5.6.3",
|
||||||
"typescript-eslint": "^8.13.0",
|
"typescript-eslint": "^8.13.0",
|
||||||
"vue-loader": "^17.0.0",
|
"vue-loader": "^17.0.0",
|
||||||
|
"vue-tsc": "^3.1.3",
|
||||||
"webpack": "^5.75.0",
|
"webpack": "^5.75.0",
|
||||||
"webpack-cli": "^5.0.1"
|
"webpack-cli": "^5.0.1"
|
||||||
},
|
},
|
||||||
@@ -80,12 +81,12 @@
|
|||||||
"dev": "encore dev",
|
"dev": "encore dev",
|
||||||
"watch": "encore dev --watch",
|
"watch": "encore dev --watch",
|
||||||
"build": "encore production --progress",
|
"build": "encore production --progress",
|
||||||
"specs-build": "yaml-merge src/Bundle/ChillMainBundle/chill.api.specs.yaml src/Bundle/ChillPersonBundle/chill.api.specs.yaml src/Bundle/ChillCalendarBundle/chill.api.specs.yaml src/Bundle/ChillThirdPartyBundle/chill.api.specs.yaml src/Bundle/ChillDocStoreBundle/chill.api.specs.yaml> templates/api/specs.yaml",
|
"specs-build": "yaml-merge src/Bundle/ChillMainBundle/chill.api.specs.yaml src/Bundle/ChillPersonBundle/chill.api.specs.yaml src/Bundle/ChillCalendarBundle/chill.api.specs.yaml src/Bundle/ChillThirdPartyBundle/chill.api.specs.yaml src/Bundle/ChillDocStoreBundle/chill.api.specs.yaml src/Bundle/ChillTicketBundle/chill.api.specs.yaml> templates/api/specs.yaml",
|
||||||
"specs-validate": "swagger-cli validate templates/api/specs.yaml",
|
"specs-validate": "swagger-cli validate templates/api/specs.yaml",
|
||||||
"specs-create-dir": "mkdir -p templates/api",
|
"specs-create-dir": "mkdir -p templates/api",
|
||||||
"specs": "yarn run specs-create-dir && yarn run specs-build && yarn run specs-validate",
|
"specs": "yarn run specs-create-dir && yarn run specs-build && yarn run specs-validate",
|
||||||
"version": "node --version",
|
"version": "node --version",
|
||||||
"eslint": "npx eslint-baseline --fix \"src/**/*.{js,ts,vue}\""
|
"eslint": "eslint-baseline --fix \"src/**/*.{js,ts,vue}\""
|
||||||
},
|
},
|
||||||
"private": true
|
"private": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,10 @@
|
|||||||
<!-- temporarily removed, the time to find a fix -->
|
<!-- temporarily removed, the time to find a fix -->
|
||||||
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php</exclude>
|
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php</exclude>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
|
|
||||||
|
<testsuite name="TicketBundle">
|
||||||
|
<directory suffix="Test.php">src/Bundle/ChillTicketBundle/tests/</directory>
|
||||||
|
</testsuite>
|
||||||
<!--
|
<!--
|
||||||
<testsuite name="ReportBundle">
|
<testsuite name="ReportBundle">
|
||||||
<directory suffix="Test.php">src/Bundle/ChillReportBundle/Tests/</directory>
|
<directory suffix="Test.php">src/Bundle/ChillReportBundle/Tests/</directory>
|
||||||
|
|||||||
8
resources/ticket_motives_import/README.md
Normal file
8
resources/ticket_motives_import/README.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
In this directory, you find an example of file for the command `chill:main:ticket_motives_import`.
|
||||||
|
|
||||||
|
This file contains a list of ticket motives to import into the system. Each entry is a dictionary with two keys: `code` and `label`. The `code` key contains the unique code for the ticket motive, and the `label` key contains the human-readable label for the ticket motive.
|
||||||
|
|
||||||
|
The `stored_objects` key contains the documents that will be associated with the tickets. They must be found in the same directory.
|
||||||
|
|
||||||
|
The command `chill:main:ticket_motives_import` uses this file to import the specified ticket motives into the system.
|
||||||
|
|
||||||
136
resources/ticket_motives_import/motives.yaml
Normal file
136
resources/ticket_motives_import/motives.yaml
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
- label:
|
||||||
|
fr: Appel famille pour annonce de décès
|
||||||
|
urgent: false
|
||||||
|
supplementary_informations:
|
||||||
|
- label:
|
||||||
|
fr: Date du décès
|
||||||
|
- label:
|
||||||
|
fr: lieu du décès (domicile ou hôpital)
|
||||||
|
- label:
|
||||||
|
fr: nom de l’hôpital
|
||||||
|
- label:
|
||||||
|
fr: service concerné
|
||||||
|
stored_objects:
|
||||||
|
- label:
|
||||||
|
fr: ☀️ De 07h à 21h
|
||||||
|
filename: 2_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 🌙 De 21h à 07h du matin
|
||||||
|
filename: 3_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 🗓️ Dimanches et jours fériés
|
||||||
|
filename: 4_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 'Appel famille pour annonce absence : hospitalisation ou consultation'
|
||||||
|
urgent: false
|
||||||
|
supplementary_informations:
|
||||||
|
- label:
|
||||||
|
fr: Quel hôpital
|
||||||
|
- label:
|
||||||
|
fr: quel service
|
||||||
|
- label:
|
||||||
|
fr: pour quelles raisons
|
||||||
|
- label:
|
||||||
|
fr: 'consultation : date et heure'
|
||||||
|
- label:
|
||||||
|
fr: hospitalisation complète ou HDJ
|
||||||
|
stored_objects:
|
||||||
|
- label:
|
||||||
|
fr: ☀️ De 07h à 21h
|
||||||
|
filename: 5_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 🌙 De 21h à 07h du matin
|
||||||
|
filename: 6_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 🗓️ Dimanches et jours fériés
|
||||||
|
filename: 7_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 'Appel famille pour annonce absence : interruption de prise en charge'
|
||||||
|
urgent: false
|
||||||
|
supplementary_informations:
|
||||||
|
- label:
|
||||||
|
fr: Pour quelles raisons ? Date
|
||||||
|
- label:
|
||||||
|
fr: durée
|
||||||
|
- label:
|
||||||
|
fr: accord médical ?
|
||||||
|
stored_objects:
|
||||||
|
- label:
|
||||||
|
fr: ☀️ De 07h à 21h
|
||||||
|
filename: 8_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 🌙 De 21h à 07h du matin
|
||||||
|
filename: 9_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 🗓️ Dimanches et jours fériés
|
||||||
|
filename: 10_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 'Appel famille pour annonce absence : changement d’adresse'
|
||||||
|
urgent: false
|
||||||
|
supplementary_informations:
|
||||||
|
- label:
|
||||||
|
fr: Où
|
||||||
|
- label:
|
||||||
|
fr: Pourquoi ? Pour combien de temps ? Besoin d’un relais des soins ? Nouvelle adresse ?
|
||||||
|
stored_objects:
|
||||||
|
- label:
|
||||||
|
fr: ☀️ De 07h à 21h
|
||||||
|
filename: 11_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 🌙 De 21h à 07h du matin
|
||||||
|
filename: 12_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 🗓️ Dimanches et jours fériés
|
||||||
|
filename: 13_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: Appel famille pour altération de l’état général du patient
|
||||||
|
urgent: true
|
||||||
|
supplementary_informations:
|
||||||
|
- label:
|
||||||
|
fr: Recherche des symptômes
|
||||||
|
- label:
|
||||||
|
fr: Attentes par rapport à la demande
|
||||||
|
stored_objects:
|
||||||
|
- label:
|
||||||
|
fr: ☀️ De 07h à 21h
|
||||||
|
filename: 14_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 🌙 De 21h à 07h du matin
|
||||||
|
filename: 15_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 🗓️ Dimanches et jours fériés
|
||||||
|
filename: 16_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: Appel famille pour prise en charge de la douleur
|
||||||
|
urgent: true
|
||||||
|
supplementary_informations:
|
||||||
|
- label:
|
||||||
|
fr: Localisation douleur
|
||||||
|
- label:
|
||||||
|
fr: Horaire dernier passage
|
||||||
|
- label:
|
||||||
|
fr: Traitements en cours
|
||||||
|
stored_objects:
|
||||||
|
- label:
|
||||||
|
fr: ☀️ De 07h à 21h
|
||||||
|
filename: 17_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 🌙 De 21h à 07h du matin
|
||||||
|
filename: 18_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 🗓️ Dimanches et jours fériés
|
||||||
|
filename: 19_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: Appel famille pour information sur la date de prise en charge
|
||||||
|
urgent: false
|
||||||
|
supplementary_informations: []
|
||||||
|
stored_objects:
|
||||||
|
- label:
|
||||||
|
fr: ☀️ De 07h à 21h
|
||||||
|
filename: 20_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 🌙 De 21h à 07h du matin
|
||||||
|
filename: 21_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
|
- label:
|
||||||
|
fr: 🗓️ Dimanches et jours fériés
|
||||||
|
filename: 22_doc_20250402_Pelotons flux externes consolidés.pdf
|
||||||
6
resources/translation_override/README.md
Normal file
6
resources/translation_override/README.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
In this directory, you find an example of file for the command `chill:main:override_translation`.
|
||||||
|
|
||||||
|
This file contains a list of translations to override in the translation catalogue. Each entry is a dictionary with two keys: `from` and `to`. The `from` key contains the original translation string, and the `to` key contains the replacement string.
|
||||||
|
|
||||||
|
The command `chill:main:override_translation` uses this file to generate a new translation catalogue with the specified overrides applied.
|
||||||
|
|
||||||
8
resources/translation_override/overrides.yaml
Normal file
8
resources/translation_override/overrides.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
- {from: "de l'usager", to: "du patient"}
|
||||||
|
- {from: "l'usager", to: "le patient"}
|
||||||
|
- {from: "L'usager", to: "Le patient"}
|
||||||
|
- {from: "d'usagers", to: "de patients"}
|
||||||
|
- {from: "usagers", to: "patients"}
|
||||||
|
- {from: "Usagers", to: "Patients"}
|
||||||
|
- {from: "usager", to: "patient"}
|
||||||
|
- {from: "Usager", to: "Patient"}
|
||||||
@@ -66,6 +66,9 @@ class ListActivityHelper
|
|||||||
->leftJoin('activity.location', 'location')
|
->leftJoin('activity.location', 'location')
|
||||||
->addSelect('location.name AS locationName')
|
->addSelect('location.name AS locationName')
|
||||||
->addSelect('activity.sentReceived')
|
->addSelect('activity.sentReceived')
|
||||||
|
->addSelect('activity.comment.comment AS commentText')
|
||||||
|
->addSelect('activity.comment.date AS commentDate')
|
||||||
|
->addSelect('JSON_BUILD_OBJECT(\'uid\', activity.comment.userId, \'d\', activity.comment.date) AS commentUser')
|
||||||
->addSelect('JSON_BUILD_OBJECT(\'uid\', IDENTITY(activity.createdBy), \'d\', activity.createdAt) AS createdBy')
|
->addSelect('JSON_BUILD_OBJECT(\'uid\', IDENTITY(activity.createdBy), \'d\', activity.createdAt) AS createdBy')
|
||||||
->addSelect('activity.createdAt')
|
->addSelect('activity.createdAt')
|
||||||
->addSelect('JSON_BUILD_OBJECT(\'uid\', IDENTITY(activity.updatedBy), \'d\', activity.updatedAt) AS updatedBy')
|
->addSelect('JSON_BUILD_OBJECT(\'uid\', IDENTITY(activity.updatedBy), \'d\', activity.updatedAt) AS updatedBy')
|
||||||
@@ -87,6 +90,8 @@ class ListActivityHelper
|
|||||||
'createdAt', 'updatedAt' => $this->dateTimeHelper->getLabel($key),
|
'createdAt', 'updatedAt' => $this->dateTimeHelper->getLabel($key),
|
||||||
'createdBy', 'updatedBy' => $this->userHelper->getLabel($key, $values, $key),
|
'createdBy', 'updatedBy' => $this->userHelper->getLabel($key, $values, $key),
|
||||||
'date' => $this->dateTimeHelper->getLabel(self::MSG_KEY.$key),
|
'date' => $this->dateTimeHelper->getLabel(self::MSG_KEY.$key),
|
||||||
|
'commentDate' => $this->dateTimeHelper->getLabel(self::MSG_KEY.'comment_date'),
|
||||||
|
'commentUser' => $this->userHelper->getLabel($key, $values, self::MSG_KEY.'comment_user'),
|
||||||
'attendeeName' => function ($value) {
|
'attendeeName' => function ($value) {
|
||||||
if ('_header' === $value) {
|
if ('_header' === $value) {
|
||||||
return 'Attendee';
|
return 'Attendee';
|
||||||
@@ -176,6 +181,9 @@ class ListActivityHelper
|
|||||||
'usersNames',
|
'usersNames',
|
||||||
'thirdPartiesIds',
|
'thirdPartiesIds',
|
||||||
'thirdPartiesNames',
|
'thirdPartiesNames',
|
||||||
|
'commentText',
|
||||||
|
'commentDate',
|
||||||
|
'commentUser',
|
||||||
'createdBy',
|
'createdBy',
|
||||||
'createdAt',
|
'createdAt',
|
||||||
'updatedBy',
|
'updatedBy',
|
||||||
|
|||||||
@@ -90,7 +90,9 @@ class ActivityReasonFilter implements ExportElementValidatedInterface, FilterInt
|
|||||||
|
|
||||||
public function getFormDefaultData(): array
|
public function getFormDefaultData(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [
|
||||||
|
'reasons' => [],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function describeAction($data, ExportGenerationContext $context): string|\Symfony\Contracts\Translation\TranslatableInterface|array
|
public function describeAction($data, ExportGenerationContext $context): string|\Symfony\Contracts\Translation\TranslatableInterface|array
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ final readonly class PersonHavingActivityBetweenDateFilter implements ExportElem
|
|||||||
|
|
||||||
public function alterQuery(QueryBuilder $qb, $data, ExportGenerationContext $exportGenerationContext): void
|
public function alterQuery(QueryBuilder $qb, $data, ExportGenerationContext $exportGenerationContext): void
|
||||||
{
|
{
|
||||||
|
error_log('alterQuery called with data: '.json_encode(array_keys($data)));
|
||||||
|
|
||||||
// create a subquery for activity
|
// create a subquery for activity
|
||||||
$sqb = $qb->getEntityManager()->createQueryBuilder();
|
$sqb = $qb->getEntityManager()->createQueryBuilder();
|
||||||
$sqb->select('1')
|
$sqb->select('1')
|
||||||
@@ -59,7 +61,6 @@ final readonly class PersonHavingActivityBetweenDateFilter implements ExportElem
|
|||||||
if (\in_array('activity', $qb->getAllAliases(), true)) {
|
if (\in_array('activity', $qb->getAllAliases(), true)) {
|
||||||
$sqb->andWhere('activity_person_having_activity.id = activity.id');
|
$sqb->andWhere('activity_person_having_activity.id = activity.id');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($data['reasons']) && [] !== $data['reasons']) {
|
if (isset($data['reasons']) && [] !== $data['reasons']) {
|
||||||
// add clause activity reason
|
// add clause activity reason
|
||||||
$sqb->join('activity_person_having_activity.reasons', 'reasons_person_having_activity');
|
$sqb->join('activity_person_having_activity.reasons', 'reasons_person_having_activity');
|
||||||
@@ -124,12 +125,38 @@ final readonly class PersonHavingActivityBetweenDateFilter implements ExportElem
|
|||||||
|
|
||||||
public function normalizeFormData(array $formData): array
|
public function normalizeFormData(array $formData): array
|
||||||
{
|
{
|
||||||
return ['date_from_rolling' => $formData['date_from_rolling']->normalize(), 'date_to_rolling' => $formData['date_to_rolling']->normalize()];
|
$normalized = [
|
||||||
|
'date_from_rolling' => $formData['date_from_rolling']->normalize(),
|
||||||
|
'date_to_rolling' => $formData['date_to_rolling']->normalize(),
|
||||||
|
'reasons' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isset($formData['reasons']) && [] !== $formData['reasons']) {
|
||||||
|
$normalized['reasons'] = array_map(
|
||||||
|
fn (ActivityReason $reason) => $reason->getId(),
|
||||||
|
$formData['reasons']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function denormalizeFormData(array $formData, int $fromVersion): array
|
public function denormalizeFormData(array $formData, int $fromVersion): array
|
||||||
{
|
{
|
||||||
return ['date_from_rolling' => RollingDate::fromNormalized($formData['date_from_rolling']), 'date_to_rolling' => RollingDate::fromNormalized($formData['date_to_rolling'])];
|
$denormalized = [
|
||||||
|
'date_from_rolling' => RollingDate::fromNormalized($formData['date_from_rolling']),
|
||||||
|
'date_to_rolling' => RollingDate::fromNormalized($formData['date_to_rolling']),
|
||||||
|
'reasons' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isset($formData['reasons']) && [] !== $formData['reasons']) {
|
||||||
|
$denormalized['reasons'] = array_map(
|
||||||
|
fn ($id) => $this->activityReasonRepository->find($id),
|
||||||
|
$formData['reasons']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $denormalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFormDefaultData(): array
|
public function getFormDefaultData(): array
|
||||||
@@ -143,10 +170,12 @@ final readonly class PersonHavingActivityBetweenDateFilter implements ExportElem
|
|||||||
|
|
||||||
public function describeAction($data, ExportGenerationContext $context): array
|
public function describeAction($data, ExportGenerationContext $context): array
|
||||||
{
|
{
|
||||||
|
$reasons = $data['reasons'] ?? [];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
[] === $data['reasons'] ?
|
[] === $reasons ?
|
||||||
'export.filter.person_between_dates.describe_action_with_no_subject'
|
'export.filter.activity.describe_action_with_no_subject'
|
||||||
: 'export.filter.person_between_dates.describe_action_with_subject',
|
: 'export.filter.activity.describe_action_with_subject',
|
||||||
[
|
[
|
||||||
'date_from' => $this->rollingDateConverter->convert($data['date_from_rolling']),
|
'date_from' => $this->rollingDateConverter->convert($data['date_from_rolling']),
|
||||||
'date_to' => $this->rollingDateConverter->convert($data['date_to_rolling']),
|
'date_to' => $this->rollingDateConverter->convert($data['date_to_rolling']),
|
||||||
@@ -154,7 +183,7 @@ final readonly class PersonHavingActivityBetweenDateFilter implements ExportElem
|
|||||||
', ',
|
', ',
|
||||||
array_map(
|
array_map(
|
||||||
fn (ActivityReason $r): string => '"'.$this->translatableStringHelper->localize($r->getName()).'"',
|
fn (ActivityReason $r): string => '"'.$this->translatableStringHelper->localize($r->getName()).'"',
|
||||||
$data['reasons']
|
$reasons
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -168,6 +197,7 @@ final readonly class PersonHavingActivityBetweenDateFilter implements ExportElem
|
|||||||
|
|
||||||
public function validateForm($data, ExecutionContextInterface $context): void
|
public function validateForm($data, ExecutionContextInterface $context): void
|
||||||
{
|
{
|
||||||
|
error_log('validateForm called with data: '.json_encode(array_keys($data)));
|
||||||
if ($this->rollingDateConverter->convert($data['date_from_rolling'])
|
if ($this->rollingDateConverter->convert($data['date_from_rolling'])
|
||||||
>= $this->rollingDateConverter->convert($data['date_to_rolling'])) {
|
>= $this->rollingDateConverter->convert($data['date_to_rolling'])) {
|
||||||
$context->buildViolation('export.filter.activity.person_between_dates.date mismatch')
|
$context->buildViolation('export.filter.activity.person_between_dates.date mismatch')
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<concerned-groups v-if="hasPerson" />
|
<concerned-groups v-if="hasPerson" />
|
||||||
<social-issues-acc v-if="hasSocialIssues" />
|
<social-issues-acc v-if="hasSocialIssues" />
|
||||||
<location v-if="hasLocation" />
|
<location v-if="hasLocation" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -10,12 +10,12 @@ import SocialIssuesAcc from "./components/SocialIssuesAcc.vue";
|
|||||||
import Location from "./components/Location.vue";
|
import Location from "./components/Location.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
props: ["hasSocialIssues", "hasLocation", "hasPerson"],
|
props: ["hasSocialIssues", "hasLocation", "hasPerson"],
|
||||||
components: {
|
components: {
|
||||||
ConcernedGroups,
|
ConcernedGroups,
|
||||||
SocialIssuesAcc,
|
SocialIssuesAcc,
|
||||||
Location,
|
Location,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,46 +1,43 @@
|
|||||||
<template>
|
<template>
|
||||||
<teleport to="#add-persons" v-if="isComponentVisible">
|
<teleport to="#add-persons" v-if="isComponentVisible">
|
||||||
<div class="flex-bloc concerned-groups" :class="getContext">
|
<div class="flex-bloc concerned-groups" :class="getContext">
|
||||||
<persons-bloc
|
<persons-bloc
|
||||||
v-for="bloc in contextPersonsBlocs"
|
v-for="bloc in contextPersonsBlocs"
|
||||||
:key="bloc.key"
|
:key="bloc.key"
|
||||||
:bloc="bloc"
|
:bloc="bloc"
|
||||||
:bloc-width="getBlocWidth"
|
:bloc-width="getBlocWidth"
|
||||||
:set-persons-in-bloc="setPersonsInBloc"
|
:set-persons-in-bloc="setPersonsInBloc"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="
|
v-if="getContext === 'accompanyingCourse' && suggestedEntities.length > 0"
|
||||||
getContext === 'accompanyingCourse' &&
|
>
|
||||||
suggestedEntities.length > 0
|
<ul class="list-suggest add-items inline">
|
||||||
"
|
<li
|
||||||
|
v-for="(p, i) in suggestedEntities"
|
||||||
|
@click="addSuggestedEntity(p)"
|
||||||
|
:key="`suggestedEntities-${i}`"
|
||||||
>
|
>
|
||||||
<ul class="list-suggest add-items inline">
|
<person-text v-if="p.type === 'person'" :person="p" />
|
||||||
<li
|
<span v-else>{{ p.text }}</span>
|
||||||
v-for="(p, i) in suggestedEntities"
|
</li>
|
||||||
@click="addSuggestedEntity(p)"
|
</ul>
|
||||||
:key="`suggestedEntities-${i}`"
|
</div>
|
||||||
>
|
|
||||||
<person-text v-if="p.type === 'person'" :person="p" />
|
|
||||||
<span v-else>{{ p.text }}</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li class="add-persons">
|
<li class="add-persons">
|
||||||
<add-persons
|
<add-persons
|
||||||
:buttonTitle="trans(ACTIVITY_ADD_PERSONS)"
|
:buttonTitle="trans(ACTIVITY_ADD_PERSONS)"
|
||||||
:modalTitle="trans(ACTIVITY_ADD_PERSONS)"
|
:modalTitle="trans(ACTIVITY_ADD_PERSONS)"
|
||||||
v-bind:key="addPersons.key"
|
v-bind:key="addPersons.key"
|
||||||
v-bind:options="addPersonsOptions"
|
v-bind:options="addPersonsOptions"
|
||||||
@addNewPersons="addNewPersons"
|
@addNewPersons="addNewPersons"
|
||||||
ref="addPersons"
|
ref="addPersons"
|
||||||
>
|
>
|
||||||
</add-persons>
|
</add-persons>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</teleport>
|
</teleport>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -49,208 +46,208 @@ import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
|
|||||||
import PersonsBloc from "./ConcernedGroups/PersonsBloc.vue";
|
import PersonsBloc from "./ConcernedGroups/PersonsBloc.vue";
|
||||||
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
|
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
|
||||||
import {
|
import {
|
||||||
ACTIVITY_BLOC_PERSONS,
|
ACTIVITY_BLOC_PERSONS,
|
||||||
ACTIVITY_BLOC_PERSONS_ASSOCIATED,
|
ACTIVITY_BLOC_PERSONS_ASSOCIATED,
|
||||||
ACTIVITY_BLOC_THIRDPARTY,
|
ACTIVITY_BLOC_THIRDPARTY,
|
||||||
ACTIVITY_BLOC_USERS,
|
ACTIVITY_BLOC_USERS,
|
||||||
ACTIVITY_ADD_PERSONS,
|
ACTIVITY_ADD_PERSONS,
|
||||||
trans,
|
trans,
|
||||||
} from "translator";
|
} from "translator";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ConcernedGroups",
|
name: "ConcernedGroups",
|
||||||
components: {
|
components: {
|
||||||
AddPersons,
|
AddPersons,
|
||||||
PersonsBloc,
|
PersonsBloc,
|
||||||
PersonText,
|
PersonText,
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
trans,
|
||||||
|
ACTIVITY_ADD_PERSONS,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
personsBlocs: [
|
||||||
|
{
|
||||||
|
key: "persons",
|
||||||
|
title: trans(ACTIVITY_BLOC_PERSONS),
|
||||||
|
persons: [],
|
||||||
|
included: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "personsAssociated",
|
||||||
|
title: trans(ACTIVITY_BLOC_PERSONS_ASSOCIATED),
|
||||||
|
persons: [],
|
||||||
|
included: window.activity
|
||||||
|
? window.activity.activityType.personsVisible !== 0
|
||||||
|
: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "personsNotAssociated",
|
||||||
|
title: "activity.bloc_persons_not_associated",
|
||||||
|
persons: [],
|
||||||
|
included: window.activity
|
||||||
|
? window.activity.activityType.personsVisible !== 0
|
||||||
|
: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "thirdparty",
|
||||||
|
title: trans(ACTIVITY_BLOC_THIRDPARTY),
|
||||||
|
persons: [],
|
||||||
|
included: window.activity
|
||||||
|
? window.activity.activityType.thirdPartiesVisible !== 0
|
||||||
|
: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "users",
|
||||||
|
title: trans(ACTIVITY_BLOC_USERS),
|
||||||
|
persons: [],
|
||||||
|
included: window.activity
|
||||||
|
? window.activity.activityType.usersVisible !== 0
|
||||||
|
: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
addPersons: {
|
||||||
|
key: "activity",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isComponentVisible() {
|
||||||
|
return window.activity
|
||||||
|
? window.activity.activityType.personsVisible !== 0 ||
|
||||||
|
window.activity.activityType.thirdPartiesVisible !== 0 ||
|
||||||
|
window.activity.activityType.usersVisible !== 0
|
||||||
|
: true;
|
||||||
},
|
},
|
||||||
setup() {
|
...mapState({
|
||||||
return {
|
persons: (state) => state.activity.persons,
|
||||||
trans,
|
thirdParties: (state) => state.activity.thirdParties,
|
||||||
ACTIVITY_ADD_PERSONS,
|
users: (state) => state.activity.users,
|
||||||
};
|
accompanyingCourse: (state) => state.activity.accompanyingPeriod,
|
||||||
|
}),
|
||||||
|
...mapGetters(["suggestedEntities"]),
|
||||||
|
getContext() {
|
||||||
|
return this.accompanyingCourse ? "accompanyingCourse" : "person";
|
||||||
},
|
},
|
||||||
data() {
|
contextPersonsBlocs() {
|
||||||
return {
|
return this.personsBlocs.filter((bloc) => bloc.included !== false);
|
||||||
personsBlocs: [
|
|
||||||
{
|
|
||||||
key: "persons",
|
|
||||||
title: trans(ACTIVITY_BLOC_PERSONS),
|
|
||||||
persons: [],
|
|
||||||
included: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "personsAssociated",
|
|
||||||
title: trans(ACTIVITY_BLOC_PERSONS_ASSOCIATED),
|
|
||||||
persons: [],
|
|
||||||
included: window.activity
|
|
||||||
? window.activity.activityType.personsVisible !== 0
|
|
||||||
: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "personsNotAssociated",
|
|
||||||
title: "activity.bloc_persons_not_associated",
|
|
||||||
persons: [],
|
|
||||||
included: window.activity
|
|
||||||
? window.activity.activityType.personsVisible !== 0
|
|
||||||
: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "thirdparty",
|
|
||||||
title: trans(ACTIVITY_BLOC_THIRDPARTY),
|
|
||||||
persons: [],
|
|
||||||
included: window.activity
|
|
||||||
? window.activity.activityType.thirdPartiesVisible !== 0
|
|
||||||
: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "users",
|
|
||||||
title: trans(ACTIVITY_BLOC_USERS),
|
|
||||||
persons: [],
|
|
||||||
included: window.activity
|
|
||||||
? window.activity.activityType.usersVisible !== 0
|
|
||||||
: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
addPersons: {
|
|
||||||
key: "activity",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
computed: {
|
addPersonsOptions() {
|
||||||
isComponentVisible() {
|
let optionsType = [];
|
||||||
return window.activity
|
if (window.activity) {
|
||||||
? window.activity.activityType.personsVisible !== 0 ||
|
if (window.activity.activityType.personsVisible !== 0) {
|
||||||
window.activity.activityType.thirdPartiesVisible !== 0 ||
|
optionsType.push("person");
|
||||||
window.activity.activityType.usersVisible !== 0
|
}
|
||||||
: true;
|
if (window.activity.activityType.thirdPartiesVisible !== 0) {
|
||||||
},
|
optionsType.push("thirdparty");
|
||||||
...mapState({
|
}
|
||||||
persons: (state) => state.activity.persons,
|
if (window.activity.activityType.usersVisible !== 0) {
|
||||||
thirdParties: (state) => state.activity.thirdParties,
|
optionsType.push("user");
|
||||||
users: (state) => state.activity.users,
|
}
|
||||||
accompanyingCourse: (state) => state.activity.accompanyingPeriod,
|
} else {
|
||||||
}),
|
optionsType = ["person", "thirdparty", "user"];
|
||||||
...mapGetters(["suggestedEntities"]),
|
}
|
||||||
getContext() {
|
return {
|
||||||
return this.accompanyingCourse ? "accompanyingCourse" : "person";
|
type: optionsType,
|
||||||
},
|
priority: null,
|
||||||
contextPersonsBlocs() {
|
uniq: false,
|
||||||
return this.personsBlocs.filter((bloc) => bloc.included !== false);
|
button: {
|
||||||
},
|
size: "btn-sm",
|
||||||
addPersonsOptions() {
|
|
||||||
let optionsType = [];
|
|
||||||
if (window.activity) {
|
|
||||||
if (window.activity.activityType.personsVisible !== 0) {
|
|
||||||
optionsType.push("person");
|
|
||||||
}
|
|
||||||
if (window.activity.activityType.thirdPartiesVisible !== 0) {
|
|
||||||
optionsType.push("thirdparty");
|
|
||||||
}
|
|
||||||
if (window.activity.activityType.usersVisible !== 0) {
|
|
||||||
optionsType.push("user");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
optionsType = ["person", "thirdparty", "user"];
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
type: optionsType,
|
|
||||||
priority: null,
|
|
||||||
uniq: false,
|
|
||||||
button: {
|
|
||||||
size: "btn-sm",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
getBlocWidth() {
|
|
||||||
return Math.round(100 / this.contextPersonsBlocs.length) + "%";
|
|
||||||
},
|
},
|
||||||
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
getBlocWidth() {
|
||||||
this.setPersonsInBloc();
|
return Math.round(100 / this.contextPersonsBlocs.length) + "%";
|
||||||
},
|
},
|
||||||
methods: {
|
},
|
||||||
setPersonsInBloc() {
|
mounted() {
|
||||||
let groups;
|
this.setPersonsInBloc();
|
||||||
if (this.accompanyingCourse) {
|
},
|
||||||
groups = this.splitPersonsInGroups();
|
methods: {
|
||||||
}
|
setPersonsInBloc() {
|
||||||
this.personsBlocs.forEach((bloc) => {
|
let groups;
|
||||||
if (this.accompanyingCourse) {
|
if (this.accompanyingCourse) {
|
||||||
switch (bloc.key) {
|
groups = this.splitPersonsInGroups();
|
||||||
case "personsAssociated":
|
}
|
||||||
bloc.persons = groups.personsAssociated;
|
this.personsBlocs.forEach((bloc) => {
|
||||||
bloc.included = true;
|
if (this.accompanyingCourse) {
|
||||||
break;
|
switch (bloc.key) {
|
||||||
case "personsNotAssociated":
|
case "personsAssociated":
|
||||||
bloc.persons = groups.personsNotAssociated;
|
bloc.persons = groups.personsAssociated;
|
||||||
bloc.included = true;
|
bloc.included = true;
|
||||||
break;
|
break;
|
||||||
}
|
case "personsNotAssociated":
|
||||||
} else {
|
bloc.persons = groups.personsNotAssociated;
|
||||||
switch (bloc.key) {
|
bloc.included = true;
|
||||||
case "persons":
|
break;
|
||||||
bloc.persons = this.persons;
|
}
|
||||||
bloc.included = true;
|
} else {
|
||||||
break;
|
switch (bloc.key) {
|
||||||
}
|
case "persons":
|
||||||
}
|
bloc.persons = this.persons;
|
||||||
switch (bloc.key) {
|
bloc.included = true;
|
||||||
case "thirdparty":
|
break;
|
||||||
bloc.persons = this.thirdParties;
|
}
|
||||||
break;
|
}
|
||||||
case "users":
|
switch (bloc.key) {
|
||||||
bloc.persons = this.users;
|
case "thirdparty":
|
||||||
break;
|
bloc.persons = this.thirdParties;
|
||||||
}
|
break;
|
||||||
}, groups);
|
case "users":
|
||||||
},
|
bloc.persons = this.users;
|
||||||
splitPersonsInGroups() {
|
break;
|
||||||
let personsAssociated = [];
|
}
|
||||||
let personsNotAssociated = this.persons;
|
}, groups);
|
||||||
let participations = this.getCourseParticipations();
|
|
||||||
this.persons.forEach((person) => {
|
|
||||||
participations.forEach((participation) => {
|
|
||||||
if (person.id === participation.id) {
|
|
||||||
//console.log(person.id);
|
|
||||||
personsAssociated.push(person);
|
|
||||||
personsNotAssociated = personsNotAssociated.filter(
|
|
||||||
(p) => p !== person,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
personsAssociated: personsAssociated,
|
|
||||||
personsNotAssociated: personsNotAssociated,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
getCourseParticipations() {
|
|
||||||
let participations = [];
|
|
||||||
this.accompanyingCourse.participations.forEach((participation) => {
|
|
||||||
if (!participation.endDate) {
|
|
||||||
participations.push(participation.person);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return participations;
|
|
||||||
},
|
|
||||||
addNewPersons({ selected, modal }) {
|
|
||||||
console.log("@@@ CLICK button addNewPersons", selected);
|
|
||||||
selected.forEach((item) => {
|
|
||||||
this.$store.dispatch("addPersonsInvolved", item);
|
|
||||||
}, this);
|
|
||||||
this.$refs.addPersons.resetSearch(); // to cast child method
|
|
||||||
modal.showModal = false;
|
|
||||||
this.setPersonsInBloc();
|
|
||||||
},
|
|
||||||
addSuggestedEntity(person) {
|
|
||||||
this.$store.dispatch("addPersonsInvolved", {
|
|
||||||
result: person,
|
|
||||||
type: "person",
|
|
||||||
});
|
|
||||||
this.setPersonsInBloc();
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
splitPersonsInGroups() {
|
||||||
|
let personsAssociated = [];
|
||||||
|
let personsNotAssociated = this.persons;
|
||||||
|
let participations = this.getCourseParticipations();
|
||||||
|
this.persons.forEach((person) => {
|
||||||
|
participations.forEach((participation) => {
|
||||||
|
if (person.id === participation.id) {
|
||||||
|
//console.log(person.id);
|
||||||
|
personsAssociated.push(person);
|
||||||
|
personsNotAssociated = personsNotAssociated.filter(
|
||||||
|
(p) => p !== person,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
personsAssociated: personsAssociated,
|
||||||
|
personsNotAssociated: personsNotAssociated,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
getCourseParticipations() {
|
||||||
|
let participations = [];
|
||||||
|
this.accompanyingCourse.participations.forEach((participation) => {
|
||||||
|
if (!participation.endDate) {
|
||||||
|
participations.push(participation.person);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return participations;
|
||||||
|
},
|
||||||
|
addNewPersons({ selected, modal }) {
|
||||||
|
console.log("@@@ CLICK button addNewPersons", selected);
|
||||||
|
selected.forEach((item) => {
|
||||||
|
this.$store.dispatch("addPersonsInvolved", item);
|
||||||
|
}, this);
|
||||||
|
this.$refs.addPersons.resetSearch(); // to cast child method
|
||||||
|
modal.showModal = false;
|
||||||
|
this.setPersonsInBloc();
|
||||||
|
},
|
||||||
|
addSuggestedEntity(person) {
|
||||||
|
this.$store.dispatch("addPersonsInvolved", {
|
||||||
|
result: person,
|
||||||
|
type: "person",
|
||||||
|
});
|
||||||
|
this.setPersonsInBloc();
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
<template>
|
<template>
|
||||||
<li>
|
<li>
|
||||||
<span :title="person.text" @click.prevent="$emit('remove', person)">
|
<span :title="person.text" @click.prevent="$emit('remove', person)">
|
||||||
<span class="chill_denomination">
|
<span class="chill_denomination">
|
||||||
<person-text :person="person" :is-cut="true" />
|
<person-text :person="person" :is-cut="true" />
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
|
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PersonBadge",
|
name: "PersonBadge",
|
||||||
props: ["person"],
|
props: ["person"],
|
||||||
components: {
|
components: {
|
||||||
PersonText,
|
PersonText,
|
||||||
},
|
},
|
||||||
// computed: {
|
// computed: {
|
||||||
// textCutted() {
|
// textCutted() {
|
||||||
// let more = (this.person.text.length > 15) ?'…' : '';
|
// let more = (this.person.text.length > 15) ?'…' : '';
|
||||||
// return this.person.text.slice(0,15) + more;
|
// return this.person.text.slice(0,15) + more;
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
emits: ["remove"],
|
emits: ["remove"],
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +1,38 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="item-bloc" :style="{ 'flex-basis': blocWidth }">
|
<div class="item-bloc" :style="{ 'flex-basis': blocWidth }">
|
||||||
<div class="item-row">
|
<div class="item-row">
|
||||||
<div class="item-col">
|
<div class="item-col">
|
||||||
<h4>{{ $t(bloc.title) }}</h4>
|
<h4>{{ $t(bloc.title) }}</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-col">
|
<div class="item-col">
|
||||||
<ul class="list-suggest remove-items">
|
<ul class="list-suggest remove-items">
|
||||||
<person-badge
|
<person-badge
|
||||||
v-for="person in bloc.persons"
|
v-for="person in bloc.persons"
|
||||||
:key="person.id"
|
:key="person.id"
|
||||||
:person="person"
|
:person="person"
|
||||||
@remove="removePerson"
|
@remove="removePerson"
|
||||||
/>
|
/>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import PersonBadge from "./PersonBadge.vue";
|
import PersonBadge from "./PersonBadge.vue";
|
||||||
export default {
|
export default {
|
||||||
name: "PersonsBloc",
|
name: "PersonsBloc",
|
||||||
components: {
|
components: {
|
||||||
PersonBadge,
|
PersonBadge,
|
||||||
},
|
},
|
||||||
props: ["bloc", "setPersonsInBloc", "blocWidth"],
|
props: ["bloc", "setPersonsInBloc", "blocWidth"],
|
||||||
methods: {
|
methods: {
|
||||||
removePerson(item) {
|
removePerson(item) {
|
||||||
console.log("@@ CLICK remove person: item", item);
|
console.log("@@ CLICK remove person: item", item);
|
||||||
this.$store.dispatch("removePersonInvolved", item);
|
this.$store.dispatch("removePersonInvolved", item);
|
||||||
this.setPersonsInBloc();
|
this.setPersonsInBloc();
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,32 @@
|
|||||||
<template>
|
<template>
|
||||||
<teleport to="#location">
|
<teleport to="#location">
|
||||||
<div class="mb-3 row">
|
<div class="mb-3 row">
|
||||||
<label :class="locationClassList">
|
<label :class="locationClassList">
|
||||||
{{ trans(ACTIVITY_LOCATION) }}
|
{{ trans(ACTIVITY_LOCATION) }}
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<VueMultiselect
|
<VueMultiselect
|
||||||
name="selectLocation"
|
name="selectLocation"
|
||||||
id="selectLocation"
|
id="selectLocation"
|
||||||
label="name"
|
label="name"
|
||||||
track-by="id"
|
track-by="id"
|
||||||
open-direction="top"
|
open-direction="top"
|
||||||
:multiple="false"
|
:multiple="false"
|
||||||
:searchable="true"
|
:searchable="true"
|
||||||
:placeholder="trans(ACTIVITY_CHOOSE_LOCATION)"
|
:placeholder="trans(ACTIVITY_CHOOSE_LOCATION)"
|
||||||
:custom-label="customLabel"
|
:custom-label="customLabel"
|
||||||
:select-label="trans(MULTISELECT_SELECT_LABEL)"
|
:select-label="trans(MULTISELECT_SELECT_LABEL)"
|
||||||
:deselect-label="trans(MULTISELECT_DESELECT_LABEL)"
|
:deselect-label="trans(MULTISELECT_DESELECT_LABEL)"
|
||||||
:selected-label="trans(MULTISELECT_SELECTED_LABEL)"
|
:selected-label="trans(MULTISELECT_SELECTED_LABEL)"
|
||||||
:options="availableLocations"
|
:options="availableLocations"
|
||||||
group-values="locations"
|
group-values="locations"
|
||||||
group-label="locationGroup"
|
group-label="locationGroup"
|
||||||
v-model="location"
|
v-model="location"
|
||||||
/>
|
/>
|
||||||
<new-location v-bind:available-locations="availableLocations" />
|
<new-location v-bind:available-locations="availableLocations" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</teleport>
|
</teleport>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -35,60 +35,60 @@ import VueMultiselect from "vue-multiselect";
|
|||||||
import NewLocation from "./Location/NewLocation.vue";
|
import NewLocation from "./Location/NewLocation.vue";
|
||||||
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||||
import {
|
import {
|
||||||
trans,
|
trans,
|
||||||
ACTIVITY_LOCATION,
|
ACTIVITY_LOCATION,
|
||||||
ACTIVITY_CHOOSE_LOCATION,
|
ACTIVITY_CHOOSE_LOCATION,
|
||||||
MULTISELECT_SELECT_LABEL,
|
MULTISELECT_SELECT_LABEL,
|
||||||
MULTISELECT_DESELECT_LABEL,
|
MULTISELECT_DESELECT_LABEL,
|
||||||
MULTISELECT_SELECTED_LABEL,
|
MULTISELECT_SELECTED_LABEL,
|
||||||
} from "translator";
|
} from "translator";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Location",
|
name: "Location",
|
||||||
components: {
|
components: {
|
||||||
NewLocation,
|
NewLocation,
|
||||||
VueMultiselect,
|
VueMultiselect,
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
trans,
|
||||||
|
ACTIVITY_LOCATION,
|
||||||
|
ACTIVITY_CHOOSE_LOCATION,
|
||||||
|
MULTISELECT_SELECT_LABEL,
|
||||||
|
MULTISELECT_DESELECT_LABEL,
|
||||||
|
MULTISELECT_SELECTED_LABEL,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
locationClassList: `col-form-label col-sm-4 ${document.querySelector("input#chill_activitybundle_activity_location").getAttribute("required") ? "required" : ""}`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(["activity", "availableLocations"]),
|
||||||
|
...mapGetters(["suggestedEntities"]),
|
||||||
|
location: {
|
||||||
|
get() {
|
||||||
|
return this.activity.location;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.$store.dispatch("updateLocation", value);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setup() {
|
},
|
||||||
return {
|
methods: {
|
||||||
trans,
|
labelAccompanyingCourseLocation(value) {
|
||||||
ACTIVITY_LOCATION,
|
return `${value.address.text} (${localizeString(value.locationType.title)})`;
|
||||||
ACTIVITY_CHOOSE_LOCATION,
|
|
||||||
MULTISELECT_SELECT_LABEL,
|
|
||||||
MULTISELECT_DESELECT_LABEL,
|
|
||||||
MULTISELECT_SELECTED_LABEL,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
data() {
|
customLabel(value) {
|
||||||
return {
|
return value.locationType
|
||||||
locationClassList: `col-form-label col-sm-4 ${document.querySelector("input#chill_activitybundle_activity_location").getAttribute("required") ? "required" : ""}`,
|
? value.name
|
||||||
};
|
? value.name === "__AccompanyingCourseLocation__"
|
||||||
},
|
? this.labelAccompanyingCourseLocation(value)
|
||||||
computed: {
|
: `${value.name} (${localizeString(value.locationType.title)})`
|
||||||
...mapState(["activity", "availableLocations"]),
|
: localizeString(value.locationType.title)
|
||||||
...mapGetters(["suggestedEntities"]),
|
: "";
|
||||||
location: {
|
|
||||||
get() {
|
|
||||||
return this.activity.location;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.$store.dispatch("updateLocation", value);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
labelAccompanyingCourseLocation(value) {
|
|
||||||
return `${value.address.text} (${localizeString(value.locationType.title)})`;
|
|
||||||
},
|
|
||||||
customLabel(value) {
|
|
||||||
return value.locationType
|
|
||||||
? value.name
|
|
||||||
? value.name === "__AccompanyingCourseLocation__"
|
|
||||||
? this.labelAccompanyingCourseLocation(value)
|
|
||||||
: `${value.name} (${localizeString(value.locationType.title)})`
|
|
||||||
: localizeString(value.locationType.title)
|
|
||||||
: "";
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,123 +1,114 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li>
|
<li>
|
||||||
<a class="btn btn-sm btn-create" @click="openModal">
|
<a class="btn btn-sm btn-create" @click="openModal">
|
||||||
{{ trans(ACTIVITY_CREATE_NEW_LOCATION) }}
|
{{ trans(ACTIVITY_CREATE_NEW_LOCATION) }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<teleport to="body">
|
<teleport to="body">
|
||||||
<modal
|
<modal
|
||||||
v-if="modal.showModal"
|
v-if="modal.showModal"
|
||||||
:modalDialogClass="modal.modalDialogClass"
|
:modalDialogClass="modal.modalDialogClass"
|
||||||
@close="modal.showModal = false"
|
@close="modal.showModal = false"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<h3 class="modal-title">
|
<h3 class="modal-title">
|
||||||
{{ trans(ACTIVITY_CREATE_NEW_LOCATION) }}
|
{{ trans(ACTIVITY_CREATE_NEW_LOCATION) }}
|
||||||
</h3>
|
</h3>
|
||||||
</template>
|
</template>
|
||||||
<template #body>
|
<template #body>
|
||||||
<form>
|
<form>
|
||||||
<div class="alert alert-warning" v-if="errors.length">
|
<div class="alert alert-warning" v-if="errors.length">
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="(e, i) in errors" :key="i">
|
<li v-for="(e, i) in errors" :key="i">
|
||||||
{{ e }}
|
{{ e }}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-floating mb-3">
|
<div class="form-floating mb-3">
|
||||||
<select
|
<select
|
||||||
class="form-select form-select-lg"
|
class="form-select form-select-lg"
|
||||||
id="type"
|
id="type"
|
||||||
required
|
required
|
||||||
v-model="selectType"
|
v-model="selectType"
|
||||||
>
|
>
|
||||||
<option selected disabled value="">
|
<option selected disabled value="">
|
||||||
{{ trans(ACTIVITY_CHOOSE_LOCATION_TYPE) }}
|
{{ trans(ACTIVITY_CHOOSE_LOCATION_TYPE) }}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option v-for="t in locationTypes" :value="t" :key="t.id">
|
||||||
v-for="t in locationTypes"
|
{{ localizeString(t.title) }}
|
||||||
:value="t"
|
</option>
|
||||||
:key="t.id"
|
</select>
|
||||||
>
|
<label>{{ trans(ACTIVITY_LOCATION_FIELDS_TYPE) }}</label>
|
||||||
{{ localizeString(t.title) }}
|
</div>
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<label>{{
|
|
||||||
trans(ACTIVITY_LOCATION_FIELDS_TYPE)
|
|
||||||
}}</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-floating mb-3">
|
<div class="form-floating mb-3">
|
||||||
<input
|
<input
|
||||||
class="form-control form-control-lg"
|
class="form-control form-control-lg"
|
||||||
id="name"
|
id="name"
|
||||||
v-model="inputName"
|
v-model="inputName"
|
||||||
placeholder
|
placeholder
|
||||||
/>
|
/>
|
||||||
<label for="name">{{
|
<label for="name">{{
|
||||||
trans(ACTIVITY_LOCATION_FIELDS_NAME)
|
trans(ACTIVITY_LOCATION_FIELDS_NAME)
|
||||||
}}</label>
|
}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<add-address
|
<add-address
|
||||||
:context="addAddress.context"
|
:context="addAddress.context"
|
||||||
:options="addAddress.options"
|
:options="addAddress.options"
|
||||||
:addressChangedCallback="submitNewAddress"
|
:addressChangedCallback="submitNewAddress"
|
||||||
v-if="showAddAddress"
|
v-if="showAddAddress"
|
||||||
ref="addAddress"
|
ref="addAddress"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="form-floating mb-3" v-if="showContactData">
|
<div class="form-floating mb-3" v-if="showContactData">
|
||||||
<input
|
<input
|
||||||
class="form-control form-control-lg"
|
class="form-control form-control-lg"
|
||||||
id="phonenumber1"
|
id="phonenumber1"
|
||||||
v-model="inputPhonenumber1"
|
v-model="inputPhonenumber1"
|
||||||
placeholder
|
placeholder
|
||||||
/>
|
/>
|
||||||
<label for="phonenumber1">{{
|
<label for="phonenumber1">{{
|
||||||
trans(ACTIVITY_LOCATION_FIELDS_PHONENUMBER1)
|
trans(ACTIVITY_LOCATION_FIELDS_PHONENUMBER1)
|
||||||
}}</label>
|
}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-floating mb-3" v-if="hasPhonenumber1">
|
<div class="form-floating mb-3" v-if="hasPhonenumber1">
|
||||||
<input
|
<input
|
||||||
class="form-control form-control-lg"
|
class="form-control form-control-lg"
|
||||||
id="phonenumber2"
|
id="phonenumber2"
|
||||||
v-model="inputPhonenumber2"
|
v-model="inputPhonenumber2"
|
||||||
placeholder
|
placeholder
|
||||||
/>
|
/>
|
||||||
<label for="phonenumber2">{{
|
<label for="phonenumber2">{{
|
||||||
trans(ACTIVITY_LOCATION_FIELDS_PHONENUMBER2)
|
trans(ACTIVITY_LOCATION_FIELDS_PHONENUMBER2)
|
||||||
}}</label>
|
}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-floating mb-3" v-if="showContactData">
|
<div class="form-floating mb-3" v-if="showContactData">
|
||||||
<input
|
<input
|
||||||
class="form-control form-control-lg"
|
class="form-control form-control-lg"
|
||||||
id="email"
|
id="email"
|
||||||
v-model="inputEmail"
|
v-model="inputEmail"
|
||||||
placeholder
|
placeholder
|
||||||
/>
|
/>
|
||||||
<label for="email">{{
|
<label for="email">{{
|
||||||
trans(ACTIVITY_LOCATION_FIELDS_EMAIL)
|
trans(ACTIVITY_LOCATION_FIELDS_EMAIL)
|
||||||
}}</label>
|
}}</label>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<button
|
<button class="btn btn-save" @click.prevent="saveNewLocation">
|
||||||
class="btn btn-save"
|
{{ trans(SAVE) }}
|
||||||
@click.prevent="saveNewLocation"
|
</button>
|
||||||
>
|
</template>
|
||||||
{{ trans(SAVE) }}
|
</modal>
|
||||||
</button>
|
</teleport>
|
||||||
</template>
|
</div>
|
||||||
</modal>
|
|
||||||
</teleport>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -128,237 +119,236 @@ import { getLocationTypes } from "../../api";
|
|||||||
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
||||||
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||||
import {
|
import {
|
||||||
SAVE,
|
SAVE,
|
||||||
ACTIVITY_LOCATION_FIELDS_EMAIL,
|
ACTIVITY_LOCATION_FIELDS_EMAIL,
|
||||||
ACTIVITY_LOCATION_FIELDS_PHONENUMBER1,
|
ACTIVITY_LOCATION_FIELDS_PHONENUMBER1,
|
||||||
ACTIVITY_LOCATION_FIELDS_PHONENUMBER2,
|
ACTIVITY_LOCATION_FIELDS_PHONENUMBER2,
|
||||||
ACTIVITY_LOCATION_FIELDS_NAME,
|
ACTIVITY_LOCATION_FIELDS_NAME,
|
||||||
ACTIVITY_LOCATION_FIELDS_TYPE,
|
ACTIVITY_LOCATION_FIELDS_TYPE,
|
||||||
ACTIVITY_CHOOSE_LOCATION_TYPE,
|
ACTIVITY_CHOOSE_LOCATION_TYPE,
|
||||||
ACTIVITY_CREATE_NEW_LOCATION,
|
ACTIVITY_CREATE_NEW_LOCATION,
|
||||||
trans,
|
trans,
|
||||||
} from "translator";
|
} from "translator";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "NewLocation",
|
name: "NewLocation",
|
||||||
components: {
|
components: {
|
||||||
Modal,
|
Modal,
|
||||||
AddAddress,
|
AddAddress,
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
trans,
|
||||||
|
SAVE,
|
||||||
|
ACTIVITY_LOCATION_FIELDS_EMAIL,
|
||||||
|
ACTIVITY_LOCATION_FIELDS_PHONENUMBER1,
|
||||||
|
ACTIVITY_LOCATION_FIELDS_PHONENUMBER2,
|
||||||
|
ACTIVITY_LOCATION_FIELDS_NAME,
|
||||||
|
ACTIVITY_LOCATION_FIELDS_TYPE,
|
||||||
|
ACTIVITY_CHOOSE_LOCATION_TYPE,
|
||||||
|
ACTIVITY_CREATE_NEW_LOCATION,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
props: ["availableLocations"],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
errors: [],
|
||||||
|
selected: {
|
||||||
|
type: null,
|
||||||
|
name: null,
|
||||||
|
addressId: null,
|
||||||
|
phonenumber1: null,
|
||||||
|
phonenumber2: null,
|
||||||
|
email: null,
|
||||||
|
},
|
||||||
|
locationTypes: [],
|
||||||
|
modal: {
|
||||||
|
showModal: false,
|
||||||
|
modalDialogClass: "modal-dialog-scrollable modal-xl",
|
||||||
|
},
|
||||||
|
addAddress: {
|
||||||
|
options: {
|
||||||
|
button: {
|
||||||
|
text: {
|
||||||
|
create: "activity.create_address",
|
||||||
|
edit: "activity.edit_address",
|
||||||
|
},
|
||||||
|
size: "btn-sm",
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
create: "activity.create_address",
|
||||||
|
edit: "activity.edit_address",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
target: {
|
||||||
|
//name, id
|
||||||
|
},
|
||||||
|
edit: false,
|
||||||
|
addressId: null,
|
||||||
|
defaults: window.addaddress,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(["activity"]),
|
||||||
|
selectType: {
|
||||||
|
get() {
|
||||||
|
return this.selected.type;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.selected.type = value;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setup() {
|
inputName: {
|
||||||
return {
|
get() {
|
||||||
trans,
|
return this.selected.name;
|
||||||
SAVE,
|
},
|
||||||
ACTIVITY_LOCATION_FIELDS_EMAIL,
|
set(value) {
|
||||||
ACTIVITY_LOCATION_FIELDS_PHONENUMBER1,
|
this.selected.name = value;
|
||||||
ACTIVITY_LOCATION_FIELDS_PHONENUMBER2,
|
},
|
||||||
ACTIVITY_LOCATION_FIELDS_NAME,
|
},
|
||||||
ACTIVITY_LOCATION_FIELDS_TYPE,
|
inputEmail: {
|
||||||
ACTIVITY_CHOOSE_LOCATION_TYPE,
|
get() {
|
||||||
ACTIVITY_CREATE_NEW_LOCATION,
|
return this.selected.email;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.selected.email = value;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputPhonenumber1: {
|
||||||
|
get() {
|
||||||
|
return this.selected.phonenumber1;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.selected.phonenumber1 = value;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputPhonenumber2: {
|
||||||
|
get() {
|
||||||
|
return this.selected.phonenumber2;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.selected.phonenumber2 = value;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hasPhonenumber1() {
|
||||||
|
return (
|
||||||
|
this.selected.phonenumber1 !== null && this.selected.phonenumber1 !== ""
|
||||||
|
);
|
||||||
|
},
|
||||||
|
showAddAddress() {
|
||||||
|
let cond = false;
|
||||||
|
if (this.selected.type) {
|
||||||
|
if (this.selected.type.addressRequired !== "never") {
|
||||||
|
cond = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cond;
|
||||||
|
},
|
||||||
|
showContactData() {
|
||||||
|
let cond = false;
|
||||||
|
if (this.selected.type) {
|
||||||
|
if (this.selected.type.contactData !== "never") {
|
||||||
|
cond = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cond;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getLocationTypesList();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
localizeString,
|
||||||
|
checkForm() {
|
||||||
|
let cond = true;
|
||||||
|
this.errors = [];
|
||||||
|
if (!this.selected.type) {
|
||||||
|
this.errors.push("Type de localisation requis");
|
||||||
|
cond = false;
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
this.selected.type.addressRequired === "required" &&
|
||||||
|
!this.selected.addressId
|
||||||
|
) {
|
||||||
|
this.errors.push("Adresse requise");
|
||||||
|
cond = false;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
this.selected.type.contactData === "required" &&
|
||||||
|
!this.selected.phonenumber1
|
||||||
|
) {
|
||||||
|
this.errors.push("Numéro de téléphone requis");
|
||||||
|
cond = false;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
this.selected.type.contactData === "required" &&
|
||||||
|
!this.selected.email
|
||||||
|
) {
|
||||||
|
this.errors.push("Adresse email requise");
|
||||||
|
cond = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cond;
|
||||||
|
},
|
||||||
|
getLocationTypesList() {
|
||||||
|
getLocationTypes().then((results) => {
|
||||||
|
this.locationTypes = results.filter(
|
||||||
|
(t) => t.availableForUsers === true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
openModal() {
|
||||||
|
this.modal.showModal = true;
|
||||||
|
},
|
||||||
|
saveNewLocation() {
|
||||||
|
if (this.checkForm()) {
|
||||||
|
let body = {
|
||||||
|
type: "location",
|
||||||
|
name: this.selected.name,
|
||||||
|
locationType: {
|
||||||
|
id: this.selected.type.id,
|
||||||
|
type: "location-type",
|
||||||
|
},
|
||||||
|
phonenumber1: this.selected.phonenumber1,
|
||||||
|
phonenumber2: this.selected.phonenumber2,
|
||||||
|
email: this.selected.email,
|
||||||
};
|
};
|
||||||
},
|
if (this.selected.addressId) {
|
||||||
props: ["availableLocations"],
|
body = Object.assign(body, {
|
||||||
data() {
|
address: {
|
||||||
return {
|
id: this.selected.addressId,
|
||||||
errors: [],
|
|
||||||
selected: {
|
|
||||||
type: null,
|
|
||||||
name: null,
|
|
||||||
addressId: null,
|
|
||||||
phonenumber1: null,
|
|
||||||
phonenumber2: null,
|
|
||||||
email: null,
|
|
||||||
},
|
},
|
||||||
locationTypes: [],
|
});
|
||||||
modal: {
|
}
|
||||||
showModal: false,
|
|
||||||
modalDialogClass: "modal-dialog-scrollable modal-xl",
|
|
||||||
},
|
|
||||||
addAddress: {
|
|
||||||
options: {
|
|
||||||
button: {
|
|
||||||
text: {
|
|
||||||
create: "activity.create_address",
|
|
||||||
edit: "activity.edit_address",
|
|
||||||
},
|
|
||||||
size: "btn-sm",
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
create: "activity.create_address",
|
|
||||||
edit: "activity.edit_address",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
context: {
|
|
||||||
target: {
|
|
||||||
//name, id
|
|
||||||
},
|
|
||||||
edit: false,
|
|
||||||
addressId: null,
|
|
||||||
defaults: window.addaddress,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState(["activity"]),
|
|
||||||
selectType: {
|
|
||||||
get() {
|
|
||||||
return this.selected.type;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.selected.type = value;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
inputName: {
|
|
||||||
get() {
|
|
||||||
return this.selected.name;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.selected.name = value;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
inputEmail: {
|
|
||||||
get() {
|
|
||||||
return this.selected.email;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.selected.email = value;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
inputPhonenumber1: {
|
|
||||||
get() {
|
|
||||||
return this.selected.phonenumber1;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.selected.phonenumber1 = value;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
inputPhonenumber2: {
|
|
||||||
get() {
|
|
||||||
return this.selected.phonenumber2;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.selected.phonenumber2 = value;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hasPhonenumber1() {
|
|
||||||
return (
|
|
||||||
this.selected.phonenumber1 !== null &&
|
|
||||||
this.selected.phonenumber1 !== ""
|
|
||||||
);
|
|
||||||
},
|
|
||||||
showAddAddress() {
|
|
||||||
let cond = false;
|
|
||||||
if (this.selected.type) {
|
|
||||||
if (this.selected.type.addressRequired !== "never") {
|
|
||||||
cond = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cond;
|
|
||||||
},
|
|
||||||
showContactData() {
|
|
||||||
let cond = false;
|
|
||||||
if (this.selected.type) {
|
|
||||||
if (this.selected.type.contactData !== "never") {
|
|
||||||
cond = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cond;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.getLocationTypesList();
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
localizeString,
|
|
||||||
checkForm() {
|
|
||||||
let cond = true;
|
|
||||||
this.errors = [];
|
|
||||||
if (!this.selected.type) {
|
|
||||||
this.errors.push("Type de localisation requis");
|
|
||||||
cond = false;
|
|
||||||
} else {
|
|
||||||
if (
|
|
||||||
this.selected.type.addressRequired === "required" &&
|
|
||||||
!this.selected.addressId
|
|
||||||
) {
|
|
||||||
this.errors.push("Adresse requise");
|
|
||||||
cond = false;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
this.selected.type.contactData === "required" &&
|
|
||||||
!this.selected.phonenumber1
|
|
||||||
) {
|
|
||||||
this.errors.push("Numéro de téléphone requis");
|
|
||||||
cond = false;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
this.selected.type.contactData === "required" &&
|
|
||||||
!this.selected.email
|
|
||||||
) {
|
|
||||||
this.errors.push("Adresse email requise");
|
|
||||||
cond = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cond;
|
|
||||||
},
|
|
||||||
getLocationTypesList() {
|
|
||||||
getLocationTypes().then((results) => {
|
|
||||||
this.locationTypes = results.filter(
|
|
||||||
(t) => t.availableForUsers === true,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
openModal() {
|
|
||||||
this.modal.showModal = true;
|
|
||||||
},
|
|
||||||
saveNewLocation() {
|
|
||||||
if (this.checkForm()) {
|
|
||||||
let body = {
|
|
||||||
type: "location",
|
|
||||||
name: this.selected.name,
|
|
||||||
locationType: {
|
|
||||||
id: this.selected.type.id,
|
|
||||||
type: "location-type",
|
|
||||||
},
|
|
||||||
phonenumber1: this.selected.phonenumber1,
|
|
||||||
phonenumber2: this.selected.phonenumber2,
|
|
||||||
email: this.selected.email,
|
|
||||||
};
|
|
||||||
if (this.selected.addressId) {
|
|
||||||
body = Object.assign(body, {
|
|
||||||
address: {
|
|
||||||
id: this.selected.addressId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
makeFetch("POST", "/api/1.0/main/location.json", body)
|
makeFetch("POST", "/api/1.0/main/location.json", body)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
this.$store.dispatch("addAvailableLocationGroup", {
|
this.$store.dispatch("addAvailableLocationGroup", {
|
||||||
locationGroup: "Localisations nouvellement créées",
|
locationGroup: "Localisations nouvellement créées",
|
||||||
locations: [response],
|
locations: [response],
|
||||||
});
|
});
|
||||||
this.$store.dispatch("updateLocation", response);
|
this.$store.dispatch("updateLocation", response);
|
||||||
this.modal.showModal = false;
|
this.modal.showModal = false;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
if (error.name === "ValidationException") {
|
if (error.name === "ValidationException") {
|
||||||
for (let v of error.violations) {
|
for (let v of error.violations) {
|
||||||
this.errors.push(v);
|
this.errors.push(v);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.errors.push("An error occurred");
|
this.errors.push("An error occurred");
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
submitNewAddress(payload) {
|
}
|
||||||
this.selected.addressId = payload.addressId;
|
|
||||||
this.addAddress.context.addressId = payload.addressId;
|
|
||||||
this.addAddress.context.edit = true;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
submitNewAddress(payload) {
|
||||||
|
this.selected.addressId = payload.addressId;
|
||||||
|
this.addAddress.context.addressId = payload.addressId;
|
||||||
|
this.addAddress.context.edit = true;
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -136,8 +136,14 @@ export default {
|
|||||||
issueIsLoading: false,
|
issueIsLoading: false,
|
||||||
actionIsLoading: false,
|
actionIsLoading: false,
|
||||||
actionAreLoaded: false,
|
actionAreLoaded: false,
|
||||||
socialIssuesClassList: `col-form-label ${document.querySelector("input#chill_activitybundle_activity_socialIssues").getAttribute("required") ? "required" : ""}`,
|
socialIssuesClassList: {
|
||||||
socialActionsClassList: `col-form-label ${document.querySelector("input#chill_activitybundle_activity_socialActions").getAttribute("required") ? "required" : ""}`,
|
"col-form-label": true,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
socialActionsClassList: {
|
||||||
|
"col-form-label": true,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -158,6 +164,21 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
/* Load classNames after element is present */
|
||||||
|
const socialActionsEl = document.querySelector(
|
||||||
|
"input#chill_activitybundle_activity_socialActions",
|
||||||
|
);
|
||||||
|
if (socialActionsEl && socialActionsEl.hasAttribute("required")) {
|
||||||
|
this.socialActionsClassList.required = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const socialIssuesEl = document.querySelector(
|
||||||
|
"input#chill_activitybundle_activity_socialIssues",
|
||||||
|
);
|
||||||
|
if (socialIssuesEl && socialIssuesEl.hasAttribute("required")) {
|
||||||
|
this.socialIssuesClassList.required = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Load other issues in multiselect */
|
/* Load other issues in multiselect */
|
||||||
this.issueIsLoading = true;
|
this.issueIsLoading = true;
|
||||||
this.actionAreLoaded = false;
|
this.actionAreLoaded = false;
|
||||||
|
|||||||
@@ -1,38 +1,38 @@
|
|||||||
<template>
|
<template>
|
||||||
<span class="inline-choice">
|
<span class="inline-choice">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input
|
<input
|
||||||
class="form-check-input"
|
class="form-check-input"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
v-model="selected"
|
v-model="selected"
|
||||||
name="action"
|
name="action"
|
||||||
:id="action.id"
|
:id="action.id"
|
||||||
:value="action"
|
:value="action"
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label" :for="action.id">
|
<label class="form-check-label" :for="action.id">
|
||||||
<span class="badge bg-light text-dark" :title="action.text">{{
|
<span class="badge bg-light text-dark" :title="action.text">{{
|
||||||
action.text
|
action.text
|
||||||
}}</span>
|
}}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: "CheckSocialAction",
|
name: "CheckSocialAction",
|
||||||
props: ["action", "selection"],
|
props: ["action", "selection"],
|
||||||
emits: ["updateSelected"],
|
emits: ["updateSelected"],
|
||||||
computed: {
|
computed: {
|
||||||
selected: {
|
selected: {
|
||||||
set(value) {
|
set(value) {
|
||||||
this.$emit("updateSelected", value);
|
this.$emit("updateSelected", value);
|
||||||
},
|
},
|
||||||
get() {
|
get() {
|
||||||
return this.selection;
|
return this.selection;
|
||||||
},
|
},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -41,13 +41,13 @@ export default {
|
|||||||
@import "ChillPersonAssets/chill/scss/mixins";
|
@import "ChillPersonAssets/chill/scss/mixins";
|
||||||
@import "ChillMainAssets/chill/scss/chill_variables";
|
@import "ChillMainAssets/chill/scss/chill_variables";
|
||||||
span.badge {
|
span.badge {
|
||||||
@include badge_social($social-action-color);
|
@include badge_social($social-action-color);
|
||||||
font-size: 95%;
|
font-size: 95%;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
max-width: 100%; /* Adjust as needed */
|
max-width: 100%; /* Adjust as needed */
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,38 +1,36 @@
|
|||||||
<template>
|
<template>
|
||||||
<span class="inline-choice">
|
<span class="inline-choice">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input
|
<input
|
||||||
class="form-check-input"
|
class="form-check-input"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
v-model="selected"
|
v-model="selected"
|
||||||
name="issue"
|
name="issue"
|
||||||
:id="issue.id"
|
:id="issue.id"
|
||||||
:value="issue"
|
:value="issue"
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label" :for="issue.id">
|
<label class="form-check-label" :for="issue.id">
|
||||||
<span class="badge bg-chill-l-gray text-dark">{{
|
<span class="badge bg-chill-l-gray text-dark">{{ issue.text }}</span>
|
||||||
issue.text
|
</label>
|
||||||
}}</span>
|
</div>
|
||||||
</label>
|
</span>
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: "CheckSocialIssue",
|
name: "CheckSocialIssue",
|
||||||
props: ["issue", "selection"],
|
props: ["issue", "selection"],
|
||||||
emits: ["updateSelected"],
|
emits: ["updateSelected"],
|
||||||
computed: {
|
computed: {
|
||||||
selected: {
|
selected: {
|
||||||
set(value) {
|
set(value) {
|
||||||
this.$emit("updateSelected", value);
|
this.$emit("updateSelected", value);
|
||||||
},
|
},
|
||||||
get() {
|
get() {
|
||||||
return this.selection;
|
return this.selection;
|
||||||
},
|
},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -41,9 +39,9 @@ export default {
|
|||||||
@import "ChillPersonAssets/chill/scss/mixins";
|
@import "ChillPersonAssets/chill/scss/mixins";
|
||||||
@import "ChillMainAssets/chill/scss/chill_variables";
|
@import "ChillMainAssets/chill/scss/chill_variables";
|
||||||
span.badge {
|
span.badge {
|
||||||
@include badge_social($social-issue-color);
|
@include badge_social($social-issue-color);
|
||||||
font-size: 95%;
|
font-size: 95%;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Attendee: Présence de l'usager
|
|||||||
attendee: présence de l'usager
|
attendee: présence de l'usager
|
||||||
list_reasons: liste des sujets
|
list_reasons: liste des sujets
|
||||||
user_username: nom de l'utilisateur
|
user_username: nom de l'utilisateur
|
||||||
circle_name: nom du cercle
|
circle_name: nom du service
|
||||||
Remark: Commentaire
|
Remark: Commentaire
|
||||||
No comments: Aucun commentaire
|
No comments: Aucun commentaire
|
||||||
Add a new activity: Ajouter une nouvel échange
|
Add a new activity: Ajouter une nouvel échange
|
||||||
@@ -20,7 +20,7 @@ not present: absent
|
|||||||
Delete: Supprimer
|
Delete: Supprimer
|
||||||
Update: Mettre à jour
|
Update: Mettre à jour
|
||||||
Update activity: Modifier l'échange
|
Update activity: Modifier l'échange
|
||||||
Scope: Cercle
|
Scope: Service
|
||||||
Activity data: Données de l'échange
|
Activity data: Données de l'échange
|
||||||
Activity location: Localisation de l'échange
|
Activity location: Localisation de l'échange
|
||||||
No reason associated: Aucun sujet
|
No reason associated: Aucun sujet
|
||||||
@@ -398,13 +398,15 @@ export:
|
|||||||
sent received: Envoyé ou reçu
|
sent received: Envoyé ou reçu
|
||||||
emergency: Urgence
|
emergency: Urgence
|
||||||
accompanying course id: Identifiant du parcours
|
accompanying course id: Identifiant du parcours
|
||||||
course circles: Cercles du parcours
|
course circles: Services du parcours
|
||||||
travelTime: Durée de déplacement
|
travelTime: Durée de déplacement
|
||||||
durationTime: Durée
|
durationTime: Durée
|
||||||
id: Identifiant
|
id: Identifiant
|
||||||
List activities linked to an accompanying course: Liste les échanges liés à un parcours en fonction de différents filtres.
|
List activities linked to an accompanying course: Liste les échanges liés à un parcours en fonction de différents filtres.
|
||||||
List activity linked to a course: Liste des échanges liés à un parcours
|
List activity linked to a course: Liste des échanges liés à un parcours
|
||||||
|
commentText: Commentaire
|
||||||
|
comment_date: Date de la dernière édition du commentaire
|
||||||
|
comment_user: Dernière édition par
|
||||||
|
|
||||||
filter:
|
filter:
|
||||||
activity:
|
activity:
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte
|
|||||||
$config = $this->processConfiguration($configuration, $configs);
|
$config = $this->processConfiguration($configuration, $configs);
|
||||||
|
|
||||||
$container->setParameter('chill_aside_activity.form.time_duration', $config['form']['time_duration']);
|
$container->setParameter('chill_aside_activity.form.time_duration', $config['form']['time_duration']);
|
||||||
|
$container->setParameter('chill_aside_activity.show_concerned_persons_count', 'visible' === $config['show_concerned_persons_count']);
|
||||||
|
|
||||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
|
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
|
||||||
$loader->load('services.yaml');
|
$loader->load('services.yaml');
|
||||||
@@ -38,6 +39,24 @@ final class ChillAsideActivityExtension extends Extension implements PrependExte
|
|||||||
{
|
{
|
||||||
$this->prependRoute($container);
|
$this->prependRoute($container);
|
||||||
$this->prependCruds($container);
|
$this->prependCruds($container);
|
||||||
|
$this->prependTwigConfig($container);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function prependTwigConfig(ContainerBuilder $container)
|
||||||
|
{
|
||||||
|
// Get the configuration for this bundle
|
||||||
|
$chillAsideActivityConfig = $container->getExtensionConfig($this->getAlias());
|
||||||
|
$config = $this->processConfiguration($this->getConfiguration($chillAsideActivityConfig, $container), $chillAsideActivityConfig);
|
||||||
|
|
||||||
|
// Add configuration to twig globals
|
||||||
|
$twigConfig = [
|
||||||
|
'globals' => [
|
||||||
|
'chill_aside_activity_config' => [
|
||||||
|
'show_concerned_persons_count' => 'visible' === $config['show_concerned_persons_count'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$container->prependExtensionConfig('twig', $twigConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function prependCruds(ContainerBuilder $container)
|
protected function prependCruds(ContainerBuilder $container)
|
||||||
|
|||||||
@@ -141,6 +141,12 @@ class Configuration implements ConfigurationInterface
|
|||||||
->end()
|
->end()
|
||||||
->end()
|
->end()
|
||||||
->end()
|
->end()
|
||||||
|
->end()
|
||||||
|
->enumNode('show_concerned_persons_count')
|
||||||
|
->values(['hidden', 'visible'])
|
||||||
|
->defaultValue('hidden')
|
||||||
|
->info('Show the concerned persons count field in aside activity forms and views')
|
||||||
|
->end()
|
||||||
->end();
|
->end();
|
||||||
|
|
||||||
return $treeBuilder;
|
return $treeBuilder;
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ class AsideActivity implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
#[ORM\ManyToOne(targetEntity: User::class)]
|
#[ORM\ManyToOne(targetEntity: User::class)]
|
||||||
private User $updatedBy;
|
private User $updatedBy;
|
||||||
|
|
||||||
|
#[Assert\GreaterThanOrEqual(0)]
|
||||||
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, nullable: true)]
|
||||||
|
private ?int $concernedPersonsCount = 0;
|
||||||
|
|
||||||
public function getAgent(): ?User
|
public function getAgent(): ?User
|
||||||
{
|
{
|
||||||
return $this->agent;
|
return $this->agent;
|
||||||
@@ -186,4 +190,16 @@ class AsideActivity implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getConcernedPersonsCount(): ?int
|
||||||
|
{
|
||||||
|
return $this->concernedPersonsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setConcernedPersonsCount(?int $concernedPersonsCount): self
|
||||||
|
{
|
||||||
|
$this->concernedPersonsCount = $concernedPersonsCount;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\AsideActivityBundle\Export\Aggregator;
|
||||||
|
|
||||||
|
use Chill\AsideActivityBundle\Export\Declarations;
|
||||||
|
use Chill\MainBundle\Export\AggregatorInterface;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class ByConcernedPersonsCountAggregator implements AggregatorInterface
|
||||||
|
{
|
||||||
|
public function addRole(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alterQuery(QueryBuilder $qb, $data, \Chill\MainBundle\Export\ExportGenerationContext $exportGenerationContext): void
|
||||||
|
{
|
||||||
|
$qb->addSelect('aside.concernedPersonsCount AS by_concerned_persons_count_aggregator')
|
||||||
|
->addGroupBy('by_concerned_persons_count_aggregator');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyOn(): string
|
||||||
|
{
|
||||||
|
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder): void
|
||||||
|
{
|
||||||
|
// No form needed
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNormalizationVersion(): int
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function normalizeFormData(array $formData): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function denormalizeFormData(array $formData, int $fromVersion): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFormDefaultData(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabels($key, array $values, $data): callable
|
||||||
|
{
|
||||||
|
return function ($value): string {
|
||||||
|
if ('_header' === $value) {
|
||||||
|
return 'export.aggregator.Concerned persons count';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $value) {
|
||||||
|
return 'export.aggregator.No concerned persons count specified';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (string) $value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryKeys($data): array
|
||||||
|
{
|
||||||
|
return ['by_concerned_persons_count_aggregator'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'export.aggregator.Group by concerned persons count';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\AsideActivityBundle\Export\Export;
|
||||||
|
|
||||||
|
use Chill\AsideActivityBundle\Export\Declarations;
|
||||||
|
use Chill\AsideActivityBundle\Repository\AsideActivityRepository;
|
||||||
|
use Chill\AsideActivityBundle\Security\AsideActivityVoter;
|
||||||
|
use Chill\MainBundle\Export\ExportInterface;
|
||||||
|
use Chill\MainBundle\Export\FormatterInterface;
|
||||||
|
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||||
|
use Doctrine\ORM\Query;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
class SumConcernedPersonsCountAsideActivity implements ExportInterface, GroupedExportInterface
|
||||||
|
{
|
||||||
|
public function __construct(private readonly AsideActivityRepository $repository) {}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder) {}
|
||||||
|
|
||||||
|
public function getNormalizationVersion(): int
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function normalizeFormData(array $formData): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function denormalizeFormData(array $formData, int $fromVersion): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFormDefaultData(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllowedFormattersTypes(): array
|
||||||
|
{
|
||||||
|
return [FormatterInterface::TYPE_TABULAR];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'export.Sum concerned persons count for aside activities';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGroup(): string
|
||||||
|
{
|
||||||
|
return 'export.Exports of aside activities';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabels($key, array $values, $data)
|
||||||
|
{
|
||||||
|
if ('export_sum_concerned_persons_count' !== $key) {
|
||||||
|
throw new \LogicException("the key {$key} is not used by this export");
|
||||||
|
}
|
||||||
|
|
||||||
|
$labels = array_combine($values, $values);
|
||||||
|
$labels['_header'] = $this->getTitle();
|
||||||
|
|
||||||
|
return static fn ($value) => $labels[$value];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryKeys($data): array
|
||||||
|
{
|
||||||
|
return ['export_sum_concerned_persons_count'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResult($query, $data, \Chill\MainBundle\Export\ExportGenerationContext $context): array
|
||||||
|
{
|
||||||
|
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'export.Sum concerned persons count for aside activities';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType(): string
|
||||||
|
{
|
||||||
|
return Declarations::ASIDE_ACTIVITY_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initiateQuery(array $requiredModifiers, array $acl, array $data, \Chill\MainBundle\Export\ExportGenerationContext $context): \Doctrine\ORM\QueryBuilder
|
||||||
|
{
|
||||||
|
$qb = $this->repository->createQueryBuilder('aside');
|
||||||
|
|
||||||
|
$qb->select('SUM(COALESCE(aside.concernedPersonsCount, 0)) as export_sum_concerned_persons_count');
|
||||||
|
|
||||||
|
return $qb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requiredRole(): string
|
||||||
|
{
|
||||||
|
return AsideActivityVoter::STATS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsModifiers(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Declarations::ASIDE_ACTIVITY_TYPE,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
|||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
|
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\Form\FormEvent;
|
use Symfony\Component\Form\FormEvent;
|
||||||
use Symfony\Component\Form\FormEvents;
|
use Symfony\Component\Form\FormEvents;
|
||||||
@@ -29,11 +30,13 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
|||||||
final class AsideActivityFormType extends AbstractType
|
final class AsideActivityFormType extends AbstractType
|
||||||
{
|
{
|
||||||
private readonly array $timeChoices;
|
private readonly array $timeChoices;
|
||||||
|
private readonly bool $showConcernedPersonsCount;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ParameterBagInterface $parameterBag,
|
ParameterBagInterface $parameterBag,
|
||||||
) {
|
) {
|
||||||
$this->timeChoices = $parameterBag->get('chill_aside_activity.form.time_duration');
|
$this->timeChoices = $parameterBag->get('chill_aside_activity.form.time_duration');
|
||||||
|
$this->showConcernedPersonsCount = $parameterBag->get('chill_aside_activity.show_concerned_persons_count');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
@@ -76,6 +79,16 @@ final class AsideActivityFormType extends AbstractType
|
|||||||
->add('location', PickUserLocationType::class)
|
->add('location', PickUserLocationType::class)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
if ($this->showConcernedPersonsCount) {
|
||||||
|
$builder->add('concernedPersonsCount', IntegerType::class, [
|
||||||
|
'label' => 'Concerned persons count',
|
||||||
|
'required' => false,
|
||||||
|
'attr' => [
|
||||||
|
'min' => 0,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (['duration'] as $fieldName) {
|
foreach (['duration'] as $fieldName) {
|
||||||
$builder->get($fieldName)
|
$builder->get($fieldName)
|
||||||
->addModelTransformer($durationTimeTransformer);
|
->addModelTransformer($durationTimeTransformer);
|
||||||
|
|||||||
@@ -42,6 +42,11 @@
|
|||||||
{%- if entity.location.name is defined -%}
|
{%- if entity.location.name is defined -%}
|
||||||
<div><i class="fa fa-fw fa-map-marker"></i>{{ entity.location.name }}</div>
|
<div><i class="fa fa-fw fa-map-marker"></i>{{ entity.location.name }}</div>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
|
|
||||||
|
{%- if entity.concernedPersonsCount > 0 -%}
|
||||||
|
<div><i class="fa fa-fw fa-user"></i>{{ entity.concernedPersonsCount }}</div>
|
||||||
|
{%- endif -%}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="item-col" style="justify-content: flex-end;">
|
<div class="item-col" style="justify-content: flex-end;">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
|
|||||||
@@ -38,6 +38,11 @@
|
|||||||
<dt class="inline">{{ 'Duration'|trans }}</dt>
|
<dt class="inline">{{ 'Duration'|trans }}</dt>
|
||||||
<dd>{{ entity.duration|date('H:i') }}</dd>
|
<dd>{{ entity.duration|date('H:i') }}</dd>
|
||||||
|
|
||||||
|
{% if chill_aside_activity_config.show_concerned_persons_count == 'visible' %}
|
||||||
|
<dt class="inline">{{ 'Concerned persons count'|trans }}</dt>
|
||||||
|
<dd>{{ entity.concernedPersonsCount }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<dt class="inline">{{ 'Remark'|trans }}</dt>
|
<dt class="inline">{{ 'Remark'|trans }}</dt>
|
||||||
{%- if entity.note is empty -%}
|
{%- if entity.note is empty -%}
|
||||||
<dd>
|
<dd>
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\AsideActivityBundle\Tests\Export\Aggregator;
|
||||||
|
|
||||||
|
use Chill\AsideActivityBundle\Entity\AsideActivity;
|
||||||
|
use Chill\AsideActivityBundle\Export\Aggregator\ByConcernedPersonsCountAggregator;
|
||||||
|
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
class ByConcernedPersonsCountAggregatorTest extends AbstractAggregatorTest
|
||||||
|
{
|
||||||
|
public function getAggregator()
|
||||||
|
{
|
||||||
|
return new ByConcernedPersonsCountAggregator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getFormData(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getQueryBuilders(): iterable
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
$em = self::getContainer()->get(EntityManagerInterface::class);
|
||||||
|
|
||||||
|
return [
|
||||||
|
$em->createQueryBuilder()
|
||||||
|
->select('count(aside.id)')
|
||||||
|
->from(AsideActivity::class, 'aside'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\AsideActivityBundle\Tests\Export\Export;
|
||||||
|
|
||||||
|
use Chill\AsideActivityBundle\Export\Export\SumConcernedPersonsCountAsideActivity;
|
||||||
|
use Chill\AsideActivityBundle\Repository\AsideActivityRepository;
|
||||||
|
use Chill\MainBundle\Test\Export\AbstractExportTest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
final class SumConcernedPersonsCountAsideActivityTest extends AbstractExportTest
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExport()
|
||||||
|
{
|
||||||
|
$repository = self::getContainer()->get(AsideActivityRepository::class);
|
||||||
|
|
||||||
|
yield new SumConcernedPersonsCountAsideActivity($repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getFormData(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getModifiersCombination(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['aside_activity'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,10 @@ services:
|
|||||||
tags:
|
tags:
|
||||||
- { name: chill.export, alias: 'avg_aside_activity_duration' }
|
- { name: chill.export, alias: 'avg_aside_activity_duration' }
|
||||||
|
|
||||||
|
Chill\AsideActivityBundle\Export\Export\SumConcernedPersonsCountAsideActivity:
|
||||||
|
tags:
|
||||||
|
- { name: chill.export, alias: 'sum_aside_activity_concerned_persons_count' }
|
||||||
|
|
||||||
## Filters
|
## Filters
|
||||||
chill.aside_activity.export.date_filter:
|
chill.aside_activity.export.date_filter:
|
||||||
class: Chill\AsideActivityBundle\Export\Filter\ByDateFilter
|
class: Chill\AsideActivityBundle\Export\Filter\ByDateFilter
|
||||||
@@ -70,3 +74,7 @@ services:
|
|||||||
Chill\AsideActivityBundle\Export\Aggregator\ByLocationAggregator:
|
Chill\AsideActivityBundle\Export\Aggregator\ByLocationAggregator:
|
||||||
tags:
|
tags:
|
||||||
- { name: chill.export_aggregator, alias: 'aside_activity_location_aggregator' }
|
- { name: chill.export_aggregator, alias: 'aside_activity_location_aggregator' }
|
||||||
|
|
||||||
|
Chill\AsideActivityBundle\Export\Aggregator\ByConcernedPersonsCountAggregator:
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_aggregator, alias: 'aside_activity_concerned_persons_count_aggregator' }
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\Migrations\AsideActivity;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20251006113048 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Add concernedPersonsCount property to AsideActivity entity';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_asideactivity.asideactivity ADD concernedPersonsCount INT DEFAULT 0');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_asideactivity.AsideActivity DROP concernedPersonsCount');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ Emergency: Urgent
|
|||||||
by: "Par "
|
by: "Par "
|
||||||
location: Lieu
|
location: Lieu
|
||||||
Asideactivity location: Localisation de l'activité
|
Asideactivity location: Localisation de l'activité
|
||||||
|
Concerned persons count: Nombre d'usager concernés
|
||||||
|
|
||||||
# Crud
|
# Crud
|
||||||
crud:
|
crud:
|
||||||
@@ -177,7 +178,7 @@ export:
|
|||||||
agent_id: Utilisateur
|
agent_id: Utilisateur
|
||||||
creator_id: Créateur
|
creator_id: Créateur
|
||||||
main_scope: Service principal de l'utilisateur
|
main_scope: Service principal de l'utilisateur
|
||||||
main_center: Centre principal de l'utilisateur
|
main_center: Territoire principal de l'utilisateur
|
||||||
aside_activity_type: Catégorie d'activité annexe
|
aside_activity_type: Catégorie d'activité annexe
|
||||||
date: Date
|
date: Date
|
||||||
duration: Durée
|
duration: Durée
|
||||||
@@ -190,6 +191,7 @@ export:
|
|||||||
Count aside activities by various parameters.: Compte le nombre d'activités annexes selon divers critères
|
Count aside activities by various parameters.: Compte le nombre d'activités annexes selon divers critères
|
||||||
Average aside activities duration: Durée moyenne des activités annexes
|
Average aside activities duration: Durée moyenne des activités annexes
|
||||||
Sum aside activities duration: Durée des activités annexes
|
Sum aside activities duration: Durée des activités annexes
|
||||||
|
Sum concerned persons count for aside activities: Nombre d'usager concernés par les activités annexes
|
||||||
filter:
|
filter:
|
||||||
Filter by aside activity date: Filtrer les activités annexes par date
|
Filter by aside activity date: Filtrer les activités annexes par date
|
||||||
Filter by aside activity type: Filtrer les activités annexes par type d'activité
|
Filter by aside activity type: Filtrer les activités annexes par type d'activité
|
||||||
@@ -210,6 +212,8 @@ export:
|
|||||||
'Filtered by aside activity location: only %location%': "Filtré par localisation: uniquement %location%"
|
'Filtered by aside activity location: only %location%': "Filtré par localisation: uniquement %location%"
|
||||||
aggregator:
|
aggregator:
|
||||||
Group by aside activity type: Grouper les activités annexes par type d'activité
|
Group by aside activity type: Grouper les activités annexes par type d'activité
|
||||||
|
Group by concerned persons count: Grouper les activités annexes par nombre d'usagers conernés
|
||||||
|
Concerned persons count: Nombre d'usagers concernés
|
||||||
Aside activity type: Type d'activité annexe
|
Aside activity type: Type d'activité annexe
|
||||||
by_user_job:
|
by_user_job:
|
||||||
Aggregate by user job: Grouper les activités annexes par métier des utilisateurs
|
Aggregate by user job: Grouper les activités annexes par métier des utilisateurs
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ namespace Chill\CalendarBundle\Controller;
|
|||||||
|
|
||||||
use Chill\CalendarBundle\Entity\Calendar;
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
use Chill\CalendarBundle\Form\CalendarType;
|
use Chill\CalendarBundle\Form\CalendarType;
|
||||||
|
use Chill\CalendarBundle\Form\CancelType;
|
||||||
use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterface;
|
use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterface;
|
||||||
use Chill\CalendarBundle\Repository\CalendarACLAwareRepositoryInterface;
|
use Chill\CalendarBundle\Repository\CalendarACLAwareRepositoryInterface;
|
||||||
use Chill\CalendarBundle\Security\Voter\CalendarVoter;
|
use Chill\CalendarBundle\Security\Voter\CalendarVoter;
|
||||||
@@ -30,6 +31,7 @@ use Chill\PersonBundle\Repository\PersonRepository;
|
|||||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||||
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use http\Exception\UnexpectedValueException;
|
use http\Exception\UnexpectedValueException;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
@@ -60,6 +62,7 @@ class CalendarController extends AbstractController
|
|||||||
private readonly UserRepositoryInterface $userRepository,
|
private readonly UserRepositoryInterface $userRepository,
|
||||||
private readonly TranslatorInterface $translator,
|
private readonly TranslatorInterface $translator,
|
||||||
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
|
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
|
||||||
|
private readonly EntityManagerInterface $em,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,6 +114,55 @@ class CalendarController extends AbstractController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route(path: '/{_locale}/calendar/calendar/{id}/cancel', name: 'chill_calendar_calendar_cancel')]
|
||||||
|
public function cancelAction(Calendar $calendar, Request $request): Response
|
||||||
|
{
|
||||||
|
// Deal with sms being sent or not
|
||||||
|
// Communicate cancellation with the remote calendar.
|
||||||
|
|
||||||
|
$this->denyAccessUnlessGranted(CalendarVoter::EDIT, $calendar);
|
||||||
|
|
||||||
|
[$person, $accompanyingPeriod] = [$calendar->getPerson(), $calendar->getAccompanyingPeriod()];
|
||||||
|
|
||||||
|
$form = $this->createForm(CancelType::class, $calendar);
|
||||||
|
$form->add('submit', SubmitType::class);
|
||||||
|
|
||||||
|
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
||||||
|
$view = '@ChillCalendar/Calendar/cancelCalendarByAccompanyingCourse.html.twig';
|
||||||
|
$redirectRoute = $this->generateUrl('chill_calendar_calendar_list_by_period', ['id' => $accompanyingPeriod->getId()]);
|
||||||
|
} elseif ($person instanceof Person) {
|
||||||
|
$view = '@ChillCalendar/Calendar/cancelCalendarByPerson.html.twig';
|
||||||
|
$redirectRoute = $this->generateUrl('chill_calendar_calendar_list_by_person', ['id' => $person->getId()]);
|
||||||
|
} else {
|
||||||
|
throw new \RuntimeException('nor person or accompanying period');
|
||||||
|
}
|
||||||
|
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
|
||||||
|
$this->logger->notice('A calendar event has been cancelled', [
|
||||||
|
'by_user' => $this->getUser()->getUsername(),
|
||||||
|
'calendar_id' => $calendar->getId(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$calendar->setStatus($calendar::STATUS_CANCELED);
|
||||||
|
$calendar->setSmsStatus($calendar::SMS_CANCEL_PENDING);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$this->addFlash('success', $this->translator->trans('chill_calendar.calendar_canceled'));
|
||||||
|
|
||||||
|
return new RedirectResponse($redirectRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render($view, [
|
||||||
|
'calendar' => $calendar,
|
||||||
|
'form' => $form->createView(),
|
||||||
|
'accompanyingCourse' => $accompanyingPeriod,
|
||||||
|
'person' => $person,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit a calendar item.
|
* Edit a calendar item.
|
||||||
*/
|
*/
|
||||||
@@ -266,7 +318,7 @@ class CalendarController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->getUser() instanceof User) {
|
if (!$this->getUser() instanceof User) {
|
||||||
throw new UnauthorizedHttpException('you are not an user');
|
throw new UnauthorizedHttpException('you are not a user');
|
||||||
}
|
}
|
||||||
|
|
||||||
$view = '@ChillCalendar/Calendar/listByUser.html.twig';
|
$view = '@ChillCalendar/Calendar/listByUser.html.twig';
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CalendarBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
|
use Chill\CalendarBundle\Repository\InviteRepository;
|
||||||
|
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepositoryInterface;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
class MyInvitationsController extends AbstractController
|
||||||
|
{
|
||||||
|
public function __construct(private readonly InviteRepository $inviteRepository, private readonly PaginatorFactory $paginator, private readonly DocGeneratorTemplateRepositoryInterface $docGeneratorTemplateRepository) {}
|
||||||
|
|
||||||
|
#[Route(path: '/{_locale}/calendar/invitations/my', name: 'chill_calendar_invitations_list_my')]
|
||||||
|
public function myInvitations(Request $request): Response
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted('ROLE_USER');
|
||||||
|
|
||||||
|
$user = $this->getUser();
|
||||||
|
|
||||||
|
if (!$user instanceof User) {
|
||||||
|
throw new UnauthorizedHttpException('you are not a user');
|
||||||
|
}
|
||||||
|
|
||||||
|
$total = count($this->inviteRepository->findBy(['user' => $user]));
|
||||||
|
$paginator = $this->paginator->create($total);
|
||||||
|
|
||||||
|
$invitations = $this->inviteRepository->findBy(
|
||||||
|
['user' => $user],
|
||||||
|
['createdAt' => 'DESC'],
|
||||||
|
$paginator->getItemsPerPage(),
|
||||||
|
$paginator->getCurrentPageFirstItemNumber()
|
||||||
|
);
|
||||||
|
|
||||||
|
$view = '@ChillCalendar/Invitations/listByUser.html.twig';
|
||||||
|
|
||||||
|
return $this->render($view, [
|
||||||
|
'invitations' => $invitations,
|
||||||
|
'paginator' => $paginator,
|
||||||
|
'templates' => $this->docGeneratorTemplateRepository->findByEntity(Calendar::class),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,7 +35,7 @@ class LoadCancelReason extends Fixture implements FixtureGroupInterface
|
|||||||
$arr = [
|
$arr = [
|
||||||
['name' => CancelReason::CANCELEDBY_USER],
|
['name' => CancelReason::CANCELEDBY_USER],
|
||||||
['name' => CancelReason::CANCELEDBY_PERSON],
|
['name' => CancelReason::CANCELEDBY_PERSON],
|
||||||
['name' => CancelReason::CANCELEDBY_DONOTCOUNT],
|
['name' => CancelReason::CANCELEDBY_OTHER],
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($arr as $a) {
|
foreach ($arr as $a) {
|
||||||
|
|||||||
@@ -269,6 +269,11 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
|||||||
return $this->cancelReason;
|
return $this->cancelReason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isCanceled(): bool
|
||||||
|
{
|
||||||
|
return null !== $this->cancelReason;
|
||||||
|
}
|
||||||
|
|
||||||
public function getCenters(): ?iterable
|
public function getCenters(): ?iterable
|
||||||
{
|
{
|
||||||
return match ($this->getContext()) {
|
return match ($this->getContext()) {
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ use Doctrine\ORM\Mapping as ORM;
|
|||||||
#[ORM\Table(name: 'chill_calendar.cancel_reason')]
|
#[ORM\Table(name: 'chill_calendar.cancel_reason')]
|
||||||
class CancelReason
|
class CancelReason
|
||||||
{
|
{
|
||||||
final public const CANCELEDBY_DONOTCOUNT = 'CANCELEDBY_DONOTCOUNT';
|
final public const CANCELEDBY_OTHER = 'CANCELEDBY_OTHER';
|
||||||
|
|
||||||
final public const CANCELEDBY_PERSON = 'CANCELEDBY_PERSON';
|
final public const CANCELEDBY_PERSON = 'CANCELEDBY_PERSON';
|
||||||
|
|
||||||
final public const CANCELEDBY_USER = 'CANCELEDBY_USER';
|
final public const CANCELEDBY_USER = 'CANCELEDBY_USER';
|
||||||
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN)]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN, options: ['default' => true])]
|
||||||
private ?bool $active = null;
|
private bool $active = true;
|
||||||
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255)]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255)]
|
||||||
private ?string $canceledBy = null;
|
private ?string $canceledBy = null;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use Chill\CalendarBundle\Entity\CancelReason;
|
|||||||
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
@@ -28,7 +28,14 @@ class CancelReasonType extends AbstractType
|
|||||||
->add('active', CheckboxType::class, [
|
->add('active', CheckboxType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
])
|
])
|
||||||
->add('canceledBy', TextType::class);
|
->add('canceledBy', ChoiceType::class, [
|
||||||
|
'choices' => [
|
||||||
|
'chill_calendar.canceled_by.user' => CancelReason::CANCELEDBY_USER,
|
||||||
|
'chill_calendar.canceled_by.person' => CancelReason::CANCELEDBY_PERSON,
|
||||||
|
'chill_calendar.canceled_by.other' => CancelReason::CANCELEDBY_OTHER,
|
||||||
|
],
|
||||||
|
'required' => true,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver)
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
|||||||
42
src/Bundle/ChillCalendarBundle/Form/CancelType.php
Normal file
42
src/Bundle/ChillCalendarBundle/Form/CancelType.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CalendarBundle\Form;
|
||||||
|
|
||||||
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
|
use Chill\CalendarBundle\Entity\CancelReason;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class CancelType extends AbstractType
|
||||||
|
{
|
||||||
|
public function __construct(private readonly TranslatableStringHelperInterface $translatableStringHelper) {}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder->add('cancelReason', EntityType::class, [
|
||||||
|
'class' => CancelReason::class,
|
||||||
|
'required' => true,
|
||||||
|
'choice_label' => fn (CancelReason $cancelReason) => $this->translatableStringHelper->localize($cancelReason->getName()),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => Calendar::class,
|
||||||
|
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,13 @@ class UserMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
if ($this->security->isGranted('ROLE_USER')) {
|
if ($this->security->isGranted('ROLE_USER')) {
|
||||||
$menu->addChild('My calendar list', [
|
$menu->addChild('My calendar list', [
|
||||||
'route' => 'chill_calendar_calendar_list_my',
|
'route' => 'chill_calendar_calendar_list_my',
|
||||||
|
])
|
||||||
|
->setExtras([
|
||||||
|
'order' => 8,
|
||||||
|
'icon' => 'tasks',
|
||||||
|
]);
|
||||||
|
$menu->addChild('invite.list.title', [
|
||||||
|
'route' => 'chill_calendar_invitations_list_my',
|
||||||
])
|
])
|
||||||
->setExtras([
|
->setExtras([
|
||||||
'order' => 9,
|
'order' => 9,
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace Chill\CalendarBundle\Messenger\Doctrine;
|
|||||||
use Chill\CalendarBundle\Entity\Calendar;
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
use Chill\CalendarBundle\Messenger\Message\CalendarMessage;
|
use Chill\CalendarBundle\Messenger\Message\CalendarMessage;
|
||||||
use Chill\CalendarBundle\Messenger\Message\CalendarRemovedMessage;
|
use Chill\CalendarBundle\Messenger\Message\CalendarRemovedMessage;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
use Doctrine\ORM\Event\PostPersistEventArgs;
|
use Doctrine\ORM\Event\PostPersistEventArgs;
|
||||||
use Doctrine\ORM\Event\PostRemoveEventArgs;
|
use Doctrine\ORM\Event\PostRemoveEventArgs;
|
||||||
use Doctrine\ORM\Event\PostUpdateEventArgs;
|
use Doctrine\ORM\Event\PostUpdateEventArgs;
|
||||||
@@ -31,6 +32,17 @@ class CalendarEntityListener
|
|||||||
{
|
{
|
||||||
public function __construct(private readonly MessageBusInterface $messageBus, private readonly Security $security) {}
|
public function __construct(private readonly MessageBusInterface $messageBus, private readonly Security $security) {}
|
||||||
|
|
||||||
|
private function getAuthenticatedUser(): User
|
||||||
|
{
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
|
||||||
|
if (!$user instanceof User) {
|
||||||
|
throw new \LogicException('Expected an instance of User.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
public function postPersist(Calendar $calendar, PostPersistEventArgs $args): void
|
public function postPersist(Calendar $calendar, PostPersistEventArgs $args): void
|
||||||
{
|
{
|
||||||
if (!$calendar->preventEnqueueChanges) {
|
if (!$calendar->preventEnqueueChanges) {
|
||||||
@@ -38,7 +50,7 @@ class CalendarEntityListener
|
|||||||
new CalendarMessage(
|
new CalendarMessage(
|
||||||
$calendar,
|
$calendar,
|
||||||
CalendarMessage::CALENDAR_PERSIST,
|
CalendarMessage::CALENDAR_PERSIST,
|
||||||
$this->security->getUser()
|
$this->getAuthenticatedUser()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -50,7 +62,7 @@ class CalendarEntityListener
|
|||||||
$this->messageBus->dispatch(
|
$this->messageBus->dispatch(
|
||||||
new CalendarRemovedMessage(
|
new CalendarRemovedMessage(
|
||||||
$calendar,
|
$calendar,
|
||||||
$this->security->getUser()
|
$this->getAuthenticatedUser()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -58,12 +70,19 @@ class CalendarEntityListener
|
|||||||
|
|
||||||
public function postUpdate(Calendar $calendar, PostUpdateEventArgs $args): void
|
public function postUpdate(Calendar $calendar, PostUpdateEventArgs $args): void
|
||||||
{
|
{
|
||||||
if (!$calendar->preventEnqueueChanges) {
|
if ($calendar->getStatus() === $calendar::STATUS_CANCELED) {
|
||||||
|
$this->messageBus->dispatch(
|
||||||
|
new CalendarRemovedMessage(
|
||||||
|
$calendar,
|
||||||
|
$this->getAuthenticatedUser()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} elseif (!$calendar->preventEnqueueChanges) {
|
||||||
$this->messageBus->dispatch(
|
$this->messageBus->dispatch(
|
||||||
new CalendarMessage(
|
new CalendarMessage(
|
||||||
$calendar,
|
$calendar,
|
||||||
CalendarMessage::CALENDAR_UPDATE,
|
CalendarMessage::CALENDAR_UPDATE,
|
||||||
$this->security->getUser()
|
$this->getAuthenticatedUser()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ class CalendarRemovedMessage
|
|||||||
|
|
||||||
public function getRemoteId(): string
|
public function getRemoteId(): string
|
||||||
{
|
{
|
||||||
|
dump($this->remoteId);
|
||||||
|
|
||||||
return $this->remoteId;
|
return $this->remoteId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,6 +191,7 @@ class CalendarRepository implements ObjectRepository
|
|||||||
$qb->expr()->eq('c.mainUser', ':user'),
|
$qb->expr()->eq('c.mainUser', ':user'),
|
||||||
$qb->expr()->gte('c.startDate', ':startDate'),
|
$qb->expr()->gte('c.startDate', ':startDate'),
|
||||||
$qb->expr()->lte('c.endDate', ':endDate'),
|
$qb->expr()->lte('c.endDate', ':endDate'),
|
||||||
|
$qb->expr()->isNull('c.cancelReason'),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
->setParameters([
|
->setParameters([
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class InviteRepository implements ObjectRepository
|
|||||||
/**
|
/**
|
||||||
* @return array|Invite[]
|
* @return array|Invite[]
|
||||||
*/
|
*/
|
||||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null)
|
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
||||||
{
|
{
|
||||||
return $this->entityRepository->findBy($criteria, $orderBy, $limit, $offset);
|
return $this->entityRepository->findBy($criteria, $orderBy, $limit, $offset);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
Chill\CalendarBundle\Controller\:
|
Chill\CalendarBundle\Controller\:
|
||||||
autowire: true
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
resource: '../../../Controller'
|
resource: '../../../Controller'
|
||||||
tags: ['controller.service_arguments']
|
tags: ['controller.service_arguments']
|
||||||
|
|||||||
@@ -1,76 +1,74 @@
|
|||||||
import { EventInput } from "@fullcalendar/core";
|
import { EventInput } from "@fullcalendar/core";
|
||||||
import {
|
import {
|
||||||
DateTime,
|
DateTime,
|
||||||
Location,
|
Location,
|
||||||
User,
|
User,
|
||||||
UserAssociatedInterface,
|
UserAssociatedInterface,
|
||||||
} from "../../../ChillMainBundle/Resources/public/types";
|
} from "../../../ChillMainBundle/Resources/public/types";
|
||||||
import { Person } from "../../../ChillPersonBundle/Resources/public/types";
|
import { Person } from "../../../ChillPersonBundle/Resources/public/types";
|
||||||
|
|
||||||
export interface CalendarRange {
|
export interface CalendarRange {
|
||||||
id: number;
|
id: number;
|
||||||
endDate: DateTime;
|
endDate: DateTime;
|
||||||
startDate: DateTime;
|
startDate: DateTime;
|
||||||
user: User;
|
user: User;
|
||||||
location: Location;
|
location: Location;
|
||||||
createdAt: DateTime;
|
createdAt: DateTime;
|
||||||
createdBy: User;
|
createdBy: User;
|
||||||
updatedAt: DateTime;
|
updatedAt: DateTime;
|
||||||
updatedBy: User;
|
updatedBy: User;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CalendarRangeCreate {
|
export interface CalendarRangeCreate {
|
||||||
user: UserAssociatedInterface;
|
user: UserAssociatedInterface;
|
||||||
startDate: DateTime;
|
startDate: DateTime;
|
||||||
endDate: DateTime;
|
endDate: DateTime;
|
||||||
location: Location;
|
location: Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CalendarRangeEdit {
|
export interface CalendarRangeEdit {
|
||||||
startDate?: DateTime;
|
startDate?: DateTime;
|
||||||
endDate?: DateTime;
|
endDate?: DateTime;
|
||||||
location?: Location;
|
location?: Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Calendar {
|
export interface Calendar {
|
||||||
id: number;
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CalendarLight {
|
export interface CalendarLight {
|
||||||
id: number;
|
id: number;
|
||||||
endDate: DateTime;
|
endDate: DateTime;
|
||||||
startDate: DateTime;
|
startDate: DateTime;
|
||||||
mainUser: User;
|
mainUser: User;
|
||||||
persons: Person[];
|
persons: Person[];
|
||||||
status: "valid" | "moved" | "canceled";
|
status: "valid" | "moved" | "canceled";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CalendarRemote {
|
export interface CalendarRemote {
|
||||||
id: number;
|
id: number;
|
||||||
endDate: DateTime;
|
endDate: DateTime;
|
||||||
startDate: DateTime;
|
startDate: DateTime;
|
||||||
title: string;
|
title: string;
|
||||||
isAllDay: boolean;
|
isAllDay: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EventInputCalendarRange = EventInput & {
|
export type EventInputCalendarRange = EventInput & {
|
||||||
id: string;
|
id: string;
|
||||||
userId: number;
|
userId: number;
|
||||||
userLabel: string;
|
userLabel: string;
|
||||||
calendarRangeId: number;
|
calendarRangeId: number;
|
||||||
locationId: number;
|
locationId: number;
|
||||||
locationName: string;
|
locationName: string;
|
||||||
start: string;
|
start: string;
|
||||||
end: string;
|
end: string;
|
||||||
is: "range";
|
is: "range";
|
||||||
};
|
};
|
||||||
|
|
||||||
export function isEventInputCalendarRange(
|
export function isEventInputCalendarRange(
|
||||||
toBeDetermined: EventInputCalendarRange | EventInput,
|
toBeDetermined: EventInputCalendarRange | EventInput,
|
||||||
): toBeDetermined is EventInputCalendarRange {
|
): toBeDetermined is EventInputCalendarRange {
|
||||||
return (
|
return typeof toBeDetermined.is === "string" && toBeDetermined.is === "range";
|
||||||
typeof toBeDetermined.is === "string" && toBeDetermined.is === "range"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export {};
|
export {};
|
||||||
|
|||||||
@@ -1,119 +1,105 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :style="style" class="calendar-active">
|
<div :style="style" class="calendar-active">
|
||||||
<span class="badge-user">
|
<span class="badge-user">
|
||||||
{{ user.text }}
|
{{ user.text }}
|
||||||
<template v-if="invite !== null">
|
<template v-if="invite !== null">
|
||||||
<i v-if="invite.status === 'accepted'" class="fa fa-check" />
|
<i v-if="invite.status === 'accepted'" class="fa fa-check" />
|
||||||
<i
|
<i v-else-if="invite.status === 'declined'" class="fa fa-times" />
|
||||||
v-else-if="invite.status === 'declined'"
|
<i v-else-if="invite.status === 'pending'" class="fa fa-question-o" />
|
||||||
class="fa fa-times"
|
<i v-else-if="invite.status === 'tentative'" class="fa fa-question" />
|
||||||
/>
|
<span v-else="">{{ invite.status }}</span>
|
||||||
<i
|
</template>
|
||||||
v-else-if="invite.status === 'pending'"
|
</span>
|
||||||
class="fa fa-question-o"
|
<span class="form-check-inline form-switch">
|
||||||
/>
|
<input
|
||||||
<i
|
class="form-check-input"
|
||||||
v-else-if="invite.status === 'tentative'"
|
type="checkbox"
|
||||||
class="fa fa-question"
|
id="flexSwitchCheckDefault"
|
||||||
/>
|
v-model="rangeShow"
|
||||||
<span v-else="">{{ invite.status }}</span>
|
/>
|
||||||
</template>
|
<label
|
||||||
</span>
|
class="form-check-label"
|
||||||
<span class="form-check-inline form-switch">
|
for="flexSwitchCheckDefault"
|
||||||
<input
|
title="Disponibilités"
|
||||||
class="form-check-input"
|
><i class="fa fa-calendar-check-o"
|
||||||
type="checkbox"
|
/></label>
|
||||||
id="flexSwitchCheckDefault"
|
</span>
|
||||||
v-model="rangeShow"
|
<span class="form-check-inline form-switch">
|
||||||
/>
|
<input
|
||||||
<label
|
class="form-check-input"
|
||||||
class="form-check-label"
|
type="checkbox"
|
||||||
for="flexSwitchCheckDefault"
|
id="flexSwitchCheckDefault"
|
||||||
title="Disponibilités"
|
v-model="remoteShow"
|
||||||
><i class="fa fa-calendar-check-o"
|
/>
|
||||||
/></label>
|
<label
|
||||||
</span>
|
class="form-check-label"
|
||||||
<span class="form-check-inline form-switch">
|
for="flexSwitchCheckDefault"
|
||||||
<input
|
title="Agenda"
|
||||||
class="form-check-input"
|
><i class="fa fa-calendar"
|
||||||
type="checkbox"
|
/></label>
|
||||||
id="flexSwitchCheckDefault"
|
</span>
|
||||||
v-model="remoteShow"
|
</div>
|
||||||
/>
|
|
||||||
<label
|
|
||||||
class="form-check-label"
|
|
||||||
for="flexSwitchCheckDefault"
|
|
||||||
title="Agenda"
|
|
||||||
><i class="fa fa-calendar"
|
|
||||||
/></label>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from "vuex";
|
import { mapGetters } from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "CalendarActive",
|
name: "CalendarActive",
|
||||||
props: {
|
props: {
|
||||||
user: {
|
user: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
|
||||||
invite: {
|
|
||||||
type: Object,
|
|
||||||
required: false,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
computed: {
|
invite: {
|
||||||
style() {
|
type: Object,
|
||||||
return {
|
required: false,
|
||||||
backgroundColor: this.$store.getters.getUserData(this.user)
|
default: null,
|
||||||
.mainColor,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
rangeShow: {
|
|
||||||
set(value) {
|
|
||||||
this.$store.commit("showUserOnCalendar", {
|
|
||||||
user: this.user,
|
|
||||||
ranges: value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
get() {
|
|
||||||
return this.$store.getters.isRangeShownOnCalendarForUser(
|
|
||||||
this.user,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
remoteShow: {
|
|
||||||
set(value) {
|
|
||||||
this.$store.commit("showUserOnCalendar", {
|
|
||||||
user: this.user,
|
|
||||||
remotes: value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
get() {
|
|
||||||
return this.$store.getters.isRemoteShownOnCalendarForUser(
|
|
||||||
this.user,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
style() {
|
||||||
|
return {
|
||||||
|
backgroundColor: this.$store.getters.getUserData(this.user).mainColor,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
rangeShow: {
|
||||||
|
set(value) {
|
||||||
|
this.$store.commit("showUserOnCalendar", {
|
||||||
|
user: this.user,
|
||||||
|
ranges: value,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.isRangeShownOnCalendarForUser(this.user);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
remoteShow: {
|
||||||
|
set(value) {
|
||||||
|
this.$store.commit("showUserOnCalendar", {
|
||||||
|
user: this.user,
|
||||||
|
remotes: value,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.isRemoteShownOnCalendarForUser(this.user);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.calendar-active {
|
.calendar-active {
|
||||||
margin: 0 0.25rem 0.25rem 0;
|
margin: 0 0.25rem 0.25rem 0;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
|
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
|
|
||||||
color: var(--bs-blue);
|
color: var(--bs-blue);
|
||||||
|
|
||||||
& > .badge-user {
|
& > .badge-user {
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -14,37 +14,37 @@ export { whoami } from "../../../../../ChillMainBundle/Resources/public/lib/api/
|
|||||||
* @return Promise
|
* @return Promise
|
||||||
*/
|
*/
|
||||||
export const fetchCalendarRangeForUser = (
|
export const fetchCalendarRangeForUser = (
|
||||||
user: User,
|
user: User,
|
||||||
start: Date,
|
start: Date,
|
||||||
end: Date,
|
end: Date,
|
||||||
): Promise<CalendarRange[]> => {
|
): Promise<CalendarRange[]> => {
|
||||||
const uri = `/api/1.0/calendar/calendar-range-available/${user.id}.json`;
|
const uri = `/api/1.0/calendar/calendar-range-available/${user.id}.json`;
|
||||||
const dateFrom = datetimeToISO(start);
|
const dateFrom = datetimeToISO(start);
|
||||||
const dateTo = datetimeToISO(end);
|
const dateTo = datetimeToISO(end);
|
||||||
|
|
||||||
return fetchResults<CalendarRange>(uri, { dateFrom, dateTo });
|
return fetchResults<CalendarRange>(uri, { dateFrom, dateTo });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchCalendarRemoteForUser = (
|
export const fetchCalendarRemoteForUser = (
|
||||||
user: User,
|
user: User,
|
||||||
start: Date,
|
start: Date,
|
||||||
end: Date,
|
end: Date,
|
||||||
): Promise<CalendarRemote[]> => {
|
): Promise<CalendarRemote[]> => {
|
||||||
const uri = `/api/1.0/calendar/proxy/calendar/by-user/${user.id}/events`;
|
const uri = `/api/1.0/calendar/proxy/calendar/by-user/${user.id}/events`;
|
||||||
const dateFrom = datetimeToISO(start);
|
const dateFrom = datetimeToISO(start);
|
||||||
const dateTo = datetimeToISO(end);
|
const dateTo = datetimeToISO(end);
|
||||||
|
|
||||||
return fetchResults<CalendarRemote>(uri, { dateFrom, dateTo });
|
return fetchResults<CalendarRemote>(uri, { dateFrom, dateTo });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchCalendarLocalForUser = (
|
export const fetchCalendarLocalForUser = (
|
||||||
user: User,
|
user: User,
|
||||||
start: Date,
|
start: Date,
|
||||||
end: Date,
|
end: Date,
|
||||||
): Promise<CalendarLight[]> => {
|
): Promise<CalendarLight[]> => {
|
||||||
const uri = `/api/1.0/calendar/calendar/by-user/${user.id}.json`;
|
const uri = `/api/1.0/calendar/calendar/by-user/${user.id}.json`;
|
||||||
const dateFrom = datetimeToISO(start);
|
const dateFrom = datetimeToISO(start);
|
||||||
const dateTo = datetimeToISO(end);
|
const dateTo = datetimeToISO(end);
|
||||||
|
|
||||||
return fetchResults<CalendarLight>(uri, { dateFrom, dateTo });
|
return fetchResults<CalendarLight>(uri, { dateFrom, dateTo });
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
const COLORS = [
|
const COLORS = [
|
||||||
/* from https://colorbrewer2.org/#type=qualitative&scheme=Set3&n=12 */
|
/* from https://colorbrewer2.org/#type=qualitative&scheme=Set3&n=12 */
|
||||||
"#8dd3c7",
|
"#8dd3c7",
|
||||||
"#ffffb3",
|
"#ffffb3",
|
||||||
"#bebada",
|
"#bebada",
|
||||||
"#fb8072",
|
"#fb8072",
|
||||||
"#80b1d3",
|
"#80b1d3",
|
||||||
"#fdb462",
|
"#fdb462",
|
||||||
"#b3de69",
|
"#b3de69",
|
||||||
"#fccde5",
|
"#fccde5",
|
||||||
"#d9d9d9",
|
"#d9d9d9",
|
||||||
"#bc80bd",
|
"#bc80bd",
|
||||||
"#ccebc5",
|
"#ccebc5",
|
||||||
"#ffed6f",
|
"#ffed6f",
|
||||||
];
|
];
|
||||||
|
|
||||||
export { COLORS };
|
export { COLORS };
|
||||||
|
|||||||
@@ -1,117 +1,117 @@
|
|||||||
import { COLORS } from "../const";
|
import { COLORS } from "../const";
|
||||||
import { ISOToDatetime } from "../../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
import { ISOToDatetime } from "../../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
||||||
import {
|
import {
|
||||||
DateTime,
|
DateTime,
|
||||||
User,
|
User,
|
||||||
} from "../../../../../../ChillMainBundle/Resources/public/types";
|
} from "../../../../../../ChillMainBundle/Resources/public/types";
|
||||||
import { CalendarLight, CalendarRange, CalendarRemote } from "../../../types";
|
import { CalendarLight, CalendarRange, CalendarRemote } from "../../../types";
|
||||||
import type { EventInputCalendarRange } from "../../../types";
|
import type { EventInputCalendarRange } from "../../../types";
|
||||||
import { EventInput } from "@fullcalendar/core";
|
import { EventInput } from "@fullcalendar/core";
|
||||||
|
|
||||||
export interface UserData {
|
export interface UserData {
|
||||||
user: User;
|
user: User;
|
||||||
calendarRanges: CalendarRange[];
|
calendarRanges: CalendarRange[];
|
||||||
calendarRangesLoaded: {}[];
|
calendarRangesLoaded: {}[];
|
||||||
remotes: CalendarRemote[];
|
remotes: CalendarRemote[];
|
||||||
remotesLoaded: {}[];
|
remotesLoaded: {}[];
|
||||||
locals: CalendarRemote[];
|
locals: CalendarRemote[];
|
||||||
localsLoaded: {}[];
|
localsLoaded: {}[];
|
||||||
mainColor: string;
|
mainColor: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const addIdToValue = (string: string, id: number): string => {
|
export const addIdToValue = (string: string, id: number): string => {
|
||||||
const array = string ? string.split(",") : [];
|
const array = string ? string.split(",") : [];
|
||||||
array.push(id.toString());
|
array.push(id.toString());
|
||||||
const str = array.join();
|
const str = array.join();
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const removeIdFromValue = (string: string, id: number) => {
|
export const removeIdFromValue = (string: string, id: number) => {
|
||||||
let array = string.split(",");
|
let array = string.split(",");
|
||||||
array = array.filter((el) => el !== id.toString());
|
array = array.filter((el) => el !== id.toString());
|
||||||
const str = array.join();
|
const str = array.join();
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Assign missing keys for the ConcernedGroups component
|
* Assign missing keys for the ConcernedGroups component
|
||||||
*/
|
*/
|
||||||
export const mapEntity = (entity: EventInput): EventInput => {
|
export const mapEntity = (entity: EventInput): EventInput => {
|
||||||
const calendar = { ...entity };
|
const calendar = { ...entity };
|
||||||
Object.assign(calendar, { thirdParties: entity.professionals });
|
Object.assign(calendar, { thirdParties: entity.professionals });
|
||||||
|
|
||||||
if (entity.startDate !== null) {
|
if (entity.startDate !== null) {
|
||||||
calendar.startDate = ISOToDatetime(entity.startDate.datetime);
|
calendar.startDate = ISOToDatetime(entity.startDate.datetime);
|
||||||
}
|
}
|
||||||
if (entity.endDate !== null) {
|
if (entity.endDate !== null) {
|
||||||
calendar.endDate = ISOToDatetime(entity.endDate.datetime);
|
calendar.endDate = ISOToDatetime(entity.endDate.datetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity.calendarRange !== null) {
|
if (entity.calendarRange !== null) {
|
||||||
calendar.calendarRange.calendarRangeId = entity.calendarRange.id;
|
calendar.calendarRange.calendarRangeId = entity.calendarRange.id;
|
||||||
calendar.calendarRange.id = `range_${entity.calendarRange.id}`;
|
calendar.calendarRange.id = `range_${entity.calendarRange.id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return calendar;
|
return calendar;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createUserData = (user: User, colorIndex: number): UserData => {
|
export const createUserData = (user: User, colorIndex: number): UserData => {
|
||||||
const colorId = colorIndex % COLORS.length;
|
const colorId = colorIndex % COLORS.length;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user: user,
|
user: user,
|
||||||
calendarRanges: [],
|
calendarRanges: [],
|
||||||
calendarRangesLoaded: [],
|
calendarRangesLoaded: [],
|
||||||
remotes: [],
|
remotes: [],
|
||||||
remotesLoaded: [],
|
remotesLoaded: [],
|
||||||
locals: [],
|
locals: [],
|
||||||
localsLoaded: [],
|
localsLoaded: [],
|
||||||
mainColor: COLORS[colorId],
|
mainColor: COLORS[colorId],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO move this function to a more global namespace, as it is also in use in MyCalendarRange app
|
// TODO move this function to a more global namespace, as it is also in use in MyCalendarRange app
|
||||||
export const calendarRangeToFullCalendarEvent = (
|
export const calendarRangeToFullCalendarEvent = (
|
||||||
entity: CalendarRange,
|
entity: CalendarRange,
|
||||||
): EventInputCalendarRange => {
|
): EventInputCalendarRange => {
|
||||||
return {
|
return {
|
||||||
id: `range_${entity.id}`,
|
id: `range_${entity.id}`,
|
||||||
title: "(" + entity.user.text + ")",
|
title: "(" + entity.user.text + ")",
|
||||||
start: entity.startDate.datetime8601,
|
start: entity.startDate.datetime8601,
|
||||||
end: entity.endDate.datetime8601,
|
end: entity.endDate.datetime8601,
|
||||||
allDay: false,
|
allDay: false,
|
||||||
userId: entity.user.id,
|
userId: entity.user.id,
|
||||||
userLabel: entity.user.label,
|
userLabel: entity.user.label,
|
||||||
calendarRangeId: entity.id,
|
calendarRangeId: entity.id,
|
||||||
locationId: entity.location.id,
|
locationId: entity.location.id,
|
||||||
locationName: entity.location.name,
|
locationName: entity.location.name,
|
||||||
is: "range",
|
is: "range",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const remoteToFullCalendarEvent = (
|
export const remoteToFullCalendarEvent = (
|
||||||
entity: CalendarRemote,
|
entity: CalendarRemote,
|
||||||
): EventInput & { id: string } => {
|
): EventInput & { id: string } => {
|
||||||
return {
|
return {
|
||||||
id: `range_${entity.id}`,
|
id: `range_${entity.id}`,
|
||||||
title: entity.title,
|
title: entity.title,
|
||||||
start: entity.startDate.datetime8601,
|
start: entity.startDate.datetime8601,
|
||||||
end: entity.endDate.datetime8601,
|
end: entity.endDate.datetime8601,
|
||||||
allDay: entity.isAllDay,
|
allDay: entity.isAllDay,
|
||||||
is: "remote",
|
is: "remote",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const localsToFullCalendarEvent = (
|
export const localsToFullCalendarEvent = (
|
||||||
entity: CalendarLight,
|
entity: CalendarLight,
|
||||||
): EventInput & { id: string; originId: number } => {
|
): EventInput & { id: string; originId: number } => {
|
||||||
return {
|
return {
|
||||||
id: `local_${entity.id}`,
|
id: `local_${entity.id}`,
|
||||||
title: entity.persons.map((p) => p.text).join(", "),
|
title: entity.persons.map((p) => p.text).join(", "),
|
||||||
originId: entity.id,
|
originId: entity.id,
|
||||||
start: entity.startDate.datetime8601,
|
start: entity.startDate.datetime8601,
|
||||||
end: entity.endDate.datetime8601,
|
end: entity.endDate.datetime8601,
|
||||||
allDay: false,
|
allDay: false,
|
||||||
is: "local",
|
is: "local",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,58 +1,50 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
<button
|
<button
|
||||||
id="btnGroupDrop1"
|
id="btnGroupDrop1"
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-misc dropdown-toggle"
|
class="btn btn-misc dropdown-toggle"
|
||||||
data-bs-toggle="dropdown"
|
data-bs-toggle="dropdown"
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
|
>
|
||||||
|
<template v-if="status === Statuses.PENDING">
|
||||||
|
<span class="fa fa-hourglass"></span> {{ $t("Give_an_answer") }}
|
||||||
|
</template>
|
||||||
|
<template v-else-if="status === Statuses.ACCEPTED">
|
||||||
|
<span class="fa fa-check"></span> {{ $t("Accepted") }}
|
||||||
|
</template>
|
||||||
|
<template v-else-if="status === Statuses.DECLINED">
|
||||||
|
<span class="fa fa-times"></span> {{ $t("Declined") }}
|
||||||
|
</template>
|
||||||
|
<template v-else-if="status === Statuses.TENTATIVELY_ACCEPTED">
|
||||||
|
<span class="fa fa-question"></span> {{ $t("Tentative") }}
|
||||||
|
</template>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
|
||||||
|
<li v-if="status !== Statuses.ACCEPTED">
|
||||||
|
<a class="dropdown-item" @click="changeStatus(Statuses.ACCEPTED)"
|
||||||
|
><i class="fa fa-check" aria-hidden="true"></i> {{ $t("Accept") }}</a
|
||||||
>
|
>
|
||||||
<template v-if="status === Statuses.PENDING">
|
</li>
|
||||||
<span class="fa fa-hourglass"></span> {{ $t("Give_an_answer") }}
|
<li v-if="status !== Statuses.DECLINED">
|
||||||
</template>
|
<a class="dropdown-item" @click="changeStatus(Statuses.DECLINED)"
|
||||||
<template v-else-if="status === Statuses.ACCEPTED">
|
><i class="fa fa-times" aria-hidden="true"></i> {{ $t("Decline") }}</a
|
||||||
<span class="fa fa-check"></span> {{ $t("Accepted") }}
|
>
|
||||||
</template>
|
</li>
|
||||||
<template v-else-if="status === Statuses.DECLINED">
|
<li v-if="status !== Statuses.TENTATIVELY_ACCEPTED">
|
||||||
<span class="fa fa-times"></span> {{ $t("Declined") }}
|
<a
|
||||||
</template>
|
class="dropdown-item"
|
||||||
<template v-else-if="status === Statuses.TENTATIVELY_ACCEPTED">
|
@click="changeStatus(Statuses.TENTATIVELY_ACCEPTED)"
|
||||||
<span class="fa fa-question"></span> {{ $t("Tentative") }}
|
><i class="fa fa-question"></i> {{ $t("Tentatively_accept") }}</a
|
||||||
</template>
|
>
|
||||||
</button>
|
</li>
|
||||||
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
|
<li v-if="status !== Statuses.PENDING">
|
||||||
<li v-if="status !== Statuses.ACCEPTED">
|
<a class="dropdown-item" @click="changeStatus(Statuses.PENDING)"
|
||||||
<a
|
><i class="fa fa-hourglass-o"></i> {{ $t("Set_pending") }}</a
|
||||||
class="dropdown-item"
|
>
|
||||||
@click="changeStatus(Statuses.ACCEPTED)"
|
</li>
|
||||||
><i class="fa fa-check" aria-hidden="true"></i>
|
</ul>
|
||||||
{{ $t("Accept") }}</a
|
</div>
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li v-if="status !== Statuses.DECLINED">
|
|
||||||
<a
|
|
||||||
class="dropdown-item"
|
|
||||||
@click="changeStatus(Statuses.DECLINED)"
|
|
||||||
><i class="fa fa-times" aria-hidden="true"></i>
|
|
||||||
{{ $t("Decline") }}</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li v-if="status !== Statuses.TENTATIVELY_ACCEPTED">
|
|
||||||
<a
|
|
||||||
class="dropdown-item"
|
|
||||||
@click="changeStatus(Statuses.TENTATIVELY_ACCEPTED)"
|
|
||||||
><i class="fa fa-question"></i>
|
|
||||||
{{ $t("Tentatively_accept") }}</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li v-if="status !== Statuses.PENDING">
|
|
||||||
<a class="dropdown-item" @click="changeStatus(Statuses.PENDING)"
|
|
||||||
><i class="fa fa-hourglass-o"></i>
|
|
||||||
{{ $t("Set_pending") }}</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -64,69 +56,67 @@ const PENDING = "pending";
|
|||||||
const TENTATIVELY_ACCEPTED = "tentative";
|
const TENTATIVELY_ACCEPTED = "tentative";
|
||||||
|
|
||||||
const i18n = {
|
const i18n = {
|
||||||
messages: {
|
messages: {
|
||||||
fr: {
|
fr: {
|
||||||
Give_an_answer: "Répondre",
|
Give_an_answer: "Répondre",
|
||||||
Accepted: "Accepté",
|
Accepted: "Accepté",
|
||||||
Declined: "Refusé",
|
Declined: "Refusé",
|
||||||
Tentative: "Accepté provisoirement",
|
Tentative: "Accepté provisoirement",
|
||||||
Accept: "Accepter",
|
Accept: "Accepter",
|
||||||
Decline: "Refuser",
|
Decline: "Refuser",
|
||||||
Tentatively_accept: "Accepter provisoirement",
|
Tentatively_accept: "Accepter provisoirement",
|
||||||
Set_pending: "Ne pas répondre",
|
Set_pending: "Ne pas répondre",
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "Answer",
|
name: "Answer",
|
||||||
i18n,
|
i18n,
|
||||||
props: {
|
props: {
|
||||||
calendarId: { type: Number, required: true },
|
calendarId: { type: Number, required: true },
|
||||||
status: {
|
status: {
|
||||||
type: String as PropType<
|
type: String as PropType<
|
||||||
"accepted" | "declined" | "pending" | "tentative"
|
"accepted" | "declined" | "pending" | "tentative"
|
||||||
>,
|
>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
emits: {
|
},
|
||||||
statusChanged(
|
emits: {
|
||||||
payload: "accepted" | "declined" | "pending" | "tentative",
|
statusChanged(payload: "accepted" | "declined" | "pending" | "tentative") {
|
||||||
) {
|
return true;
|
||||||
return true;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
data() {
|
},
|
||||||
return {
|
data() {
|
||||||
Statuses: {
|
return {
|
||||||
ACCEPTED,
|
Statuses: {
|
||||||
DECLINED,
|
ACCEPTED,
|
||||||
PENDING,
|
DECLINED,
|
||||||
TENTATIVELY_ACCEPTED,
|
PENDING,
|
||||||
},
|
TENTATIVELY_ACCEPTED,
|
||||||
};
|
},
|
||||||
},
|
};
|
||||||
methods: {
|
},
|
||||||
changeStatus: function (
|
methods: {
|
||||||
newStatus: "accepted" | "declined" | "pending" | "tentative",
|
changeStatus: function (
|
||||||
) {
|
newStatus: "accepted" | "declined" | "pending" | "tentative",
|
||||||
console.log("changeStatus", newStatus);
|
) {
|
||||||
const url = `/api/1.0/calendar/calendar/${this.$props.calendarId}/answer/${newStatus}.json`;
|
console.log("changeStatus", newStatus);
|
||||||
window
|
const url = `/api/1.0/calendar/calendar/${this.$props.calendarId}/answer/${newStatus}.json`;
|
||||||
.fetch(url, {
|
window
|
||||||
method: "POST",
|
.fetch(url, {
|
||||||
})
|
method: "POST",
|
||||||
.then((r: Response) => {
|
})
|
||||||
if (!r.ok) {
|
.then((r: Response) => {
|
||||||
console.error("could not confirm answer", newStatus);
|
if (!r.ok) {
|
||||||
return;
|
console.error("could not confirm answer", newStatus);
|
||||||
}
|
return;
|
||||||
console.log("answer sent", newStatus);
|
}
|
||||||
this.$emit("statusChanged", newStatus);
|
console.log("answer sent", newStatus);
|
||||||
});
|
this.$emit("statusChanged", newStatus);
|
||||||
},
|
});
|
||||||
},
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="Teleport" to="body">
|
<component :is="Teleport" to="body">
|
||||||
<modal v-if="showModal" @close="closeModal">
|
<modal v-if="showModal" @close="closeModal">
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
<h3>{{ "Modifier le lieu" }}</h3>
|
<h3>{{ "Modifier le lieu" }}</h3>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:body>
|
<template v-slot:body>
|
||||||
<div></div>
|
<div></div>
|
||||||
<label>Localisation</label>
|
<label>Localisation</label>
|
||||||
<vue-multiselect
|
<vue-multiselect
|
||||||
v-model="location"
|
v-model="location"
|
||||||
:options="locations"
|
:options="locations"
|
||||||
:label="'name'"
|
:label="'name'"
|
||||||
:track-by="'id'"
|
:track-by="'id'"
|
||||||
></vue-multiselect>
|
></vue-multiselect>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:footer>
|
<template v-slot:footer>
|
||||||
<button class="btn btn-save" @click="saveAndClose">
|
<button class="btn btn-save" @click="saveAndClose">
|
||||||
{{ "Enregistrer" }}
|
{{ "Enregistrer" }}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
</modal>
|
</modal>
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -39,7 +39,7 @@ import VueMultiselect from "vue-multiselect";
|
|||||||
import { Teleport as teleport_, TeleportProps, VNodeProps } from "vue";
|
import { Teleport as teleport_, TeleportProps, VNodeProps } from "vue";
|
||||||
|
|
||||||
const Teleport = teleport_ as new () => {
|
const Teleport = teleport_ as new () => {
|
||||||
$props: VNodeProps & TeleportProps;
|
$props: VNodeProps & TeleportProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
const store = useStore(key);
|
const store = useStore(key);
|
||||||
@@ -50,37 +50,37 @@ const showModal = ref(false);
|
|||||||
//const tele = ref<InstanceType<typeof Teleport> | null>(null);
|
//const tele = ref<InstanceType<typeof Teleport> | null>(null);
|
||||||
|
|
||||||
const locations = computed<Location[]>(() => {
|
const locations = computed<Location[]>(() => {
|
||||||
return store.state.locations.locations;
|
return store.state.locations.locations;
|
||||||
});
|
});
|
||||||
|
|
||||||
const startEdit = function (event: EventApi): void {
|
const startEdit = function (event: EventApi): void {
|
||||||
console.log("startEditing", event);
|
console.log("startEditing", event);
|
||||||
calendarRangeId.value = event.extendedProps.calendarRangeId;
|
calendarRangeId.value = event.extendedProps.calendarRangeId;
|
||||||
location.value =
|
location.value =
|
||||||
store.getters["locations/getLocationById"](
|
store.getters["locations/getLocationById"](
|
||||||
event.extendedProps.locationId,
|
event.extendedProps.locationId,
|
||||||
) || null;
|
) || null;
|
||||||
|
|
||||||
console.log("new location value", location.value);
|
console.log("new location value", location.value);
|
||||||
console.log("calendar range id", calendarRangeId.value);
|
console.log("calendar range id", calendarRangeId.value);
|
||||||
showModal.value = true;
|
showModal.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveAndClose = function (e: Event): void {
|
const saveAndClose = function (e: Event): void {
|
||||||
console.log("saveEditAndClose", e);
|
console.log("saveEditAndClose", e);
|
||||||
|
|
||||||
store
|
store
|
||||||
.dispatch("calendarRanges/patchRangeLocation", {
|
.dispatch("calendarRanges/patchRangeLocation", {
|
||||||
location: location.value,
|
location: location.value,
|
||||||
calendarRangeId: calendarRangeId.value,
|
calendarRangeId: calendarRangeId.value,
|
||||||
})
|
})
|
||||||
.then((_) => {
|
.then((_) => {
|
||||||
showModal.value = false;
|
showModal.value = false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeModal = function (_: any): void {
|
const closeModal = function (_: any): void {
|
||||||
showModal.value = false;
|
showModal.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
defineExpose({ startEdit });
|
defineExpose({ startEdit });
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
const appMessages = {
|
const appMessages = {
|
||||||
fr: {
|
fr: {
|
||||||
created_availabilities: "Lieu des plages de disponibilités créées",
|
created_availabilities: "Lieu des plages de disponibilités créées",
|
||||||
edit_your_calendar_range: "Planifiez vos plages de disponibilités",
|
edit_your_calendar_range: "Planifiez vos plages de disponibilités",
|
||||||
show_my_calendar: "Afficher mon calendrier",
|
show_my_calendar: "Afficher mon calendrier",
|
||||||
show_weekends: "Afficher les week-ends",
|
show_weekends: "Afficher les week-ends",
|
||||||
copy_range: "Copier",
|
copy_range: "Copier",
|
||||||
copy_range_from_to: "Copier les plages",
|
copy_range_from_to: "Copier les plages",
|
||||||
from_day_to_day: "d'un jour à l'autre",
|
from_day_to_day: "d'un jour à l'autre",
|
||||||
from_week_to_week: "d'une semaine à l'autre",
|
from_week_to_week: "d'une semaine à l'autre",
|
||||||
copy_range_how_to:
|
copy_range_how_to:
|
||||||
"Créez les plages de disponibilités durant une journée et copiez-les facilement au jour suivant avec ce bouton. Si les week-ends sont cachés, le jour suivant un vendredi sera le lundi.",
|
"Créez les plages de disponibilités durant une journée et copiez-les facilement au jour suivant avec ce bouton. Si les week-ends sont cachés, le jour suivant un vendredi sera le lundi.",
|
||||||
new_range_to_save: "Nouvelles plages à enregistrer",
|
new_range_to_save: "Nouvelles plages à enregistrer",
|
||||||
update_range_to_save: "Plages à modifier",
|
update_range_to_save: "Plages à modifier",
|
||||||
delete_range_to_save: "Plages à supprimer",
|
delete_range_to_save: "Plages à supprimer",
|
||||||
by: "Par",
|
by: "Par",
|
||||||
main_user_concerned: "Utilisateur concerné",
|
main_user_concerned: "Utilisateur concerné",
|
||||||
dateFrom: "De",
|
dateFrom: "De",
|
||||||
dateTo: "à",
|
dateTo: "à",
|
||||||
day: "Jour",
|
day: "Jour",
|
||||||
week: "Semaine",
|
week: "Semaine",
|
||||||
month: "Mois",
|
month: "Mois",
|
||||||
today: "Aujourd'hui",
|
today: "Aujourd'hui",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export { appMessages };
|
export { appMessages };
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ import App2 from "./App2.vue";
|
|||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
futureStore().then((store) => {
|
futureStore().then((store) => {
|
||||||
const i18n = _createI18n(appMessages, false);
|
const i18n = _createI18n(appMessages, false);
|
||||||
|
|
||||||
const app = createApp({
|
const app = createApp({
|
||||||
template: `<app></app>`,
|
template: `<app></app>`,
|
||||||
})
|
})
|
||||||
.use(store, key)
|
.use(store, key)
|
||||||
.use(i18n)
|
.use(i18n)
|
||||||
.component("app", App2)
|
.component("app", App2)
|
||||||
.mount("#myCalendar");
|
.mount("#myCalendar");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import me, { MeState } from "./modules/me";
|
|||||||
import fullCalendar, { FullCalendarState } from "./modules/fullcalendar";
|
import fullCalendar, { FullCalendarState } from "./modules/fullcalendar";
|
||||||
import calendarRanges, { CalendarRangesState } from "./modules/calendarRanges";
|
import calendarRanges, { CalendarRangesState } from "./modules/calendarRanges";
|
||||||
import calendarRemotes, {
|
import calendarRemotes, {
|
||||||
CalendarRemotesState,
|
CalendarRemotesState,
|
||||||
} from "./modules/calendarRemotes";
|
} from "./modules/calendarRemotes";
|
||||||
import { whoami } from "../../../../../../ChillMainBundle/Resources/public/lib/api/user";
|
import { whoami } from "../../../../../../ChillMainBundle/Resources/public/lib/api/user";
|
||||||
import { User } from "../../../../../../ChillMainBundle/Resources/public/types";
|
import { User } from "../../../../../../ChillMainBundle/Resources/public/types";
|
||||||
@@ -15,42 +15,40 @@ import calendarLocals, { CalendarLocalsState } from "./modules/calendarLocals";
|
|||||||
const debug = process.env.NODE_ENV !== "production";
|
const debug = process.env.NODE_ENV !== "production";
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
calendarRanges: CalendarRangesState;
|
calendarRanges: CalendarRangesState;
|
||||||
calendarRemotes: CalendarRemotesState;
|
calendarRemotes: CalendarRemotesState;
|
||||||
calendarLocals: CalendarLocalsState;
|
calendarLocals: CalendarLocalsState;
|
||||||
fullCalendar: FullCalendarState;
|
fullCalendar: FullCalendarState;
|
||||||
me: MeState;
|
me: MeState;
|
||||||
locations: LocationState;
|
locations: LocationState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const key: InjectionKey<Store<State>> = Symbol();
|
export const key: InjectionKey<Store<State>> = Symbol();
|
||||||
|
|
||||||
const futureStore = function (): Promise<Store<State>> {
|
const futureStore = function (): Promise<Store<State>> {
|
||||||
return whoami().then((user: User) => {
|
return whoami().then((user: User) => {
|
||||||
const store = createStore<State>({
|
const store = createStore<State>({
|
||||||
strict: debug,
|
strict: debug,
|
||||||
modules: {
|
modules: {
|
||||||
me,
|
me,
|
||||||
fullCalendar,
|
fullCalendar,
|
||||||
calendarRanges,
|
calendarRanges,
|
||||||
calendarRemotes,
|
calendarRemotes,
|
||||||
calendarLocals,
|
calendarLocals,
|
||||||
locations,
|
locations,
|
||||||
},
|
},
|
||||||
mutations: {},
|
mutations: {},
|
||||||
});
|
|
||||||
|
|
||||||
store.commit("me/setWhoAmi", user, { root: true });
|
|
||||||
store
|
|
||||||
.dispatch("locations/getLocations", null, { root: true })
|
|
||||||
.then((_) => {
|
|
||||||
return store.dispatch("locations/getCurrentLocation", null, {
|
|
||||||
root: true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.resolve(store);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
store.commit("me/setWhoAmi", user, { root: true });
|
||||||
|
store.dispatch("locations/getLocations", null, { root: true }).then((_) => {
|
||||||
|
return store.dispatch("locations/getCurrentLocation", null, {
|
||||||
|
root: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.resolve(store);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default futureStore;
|
export default futureStore;
|
||||||
|
|||||||
@@ -8,109 +8,99 @@ import { TransportExceptionInterface } from "../../../../../../../ChillMainBundl
|
|||||||
import { COLORS } from "../../../Calendar/const";
|
import { COLORS } from "../../../Calendar/const";
|
||||||
|
|
||||||
export interface CalendarLocalsState {
|
export interface CalendarLocalsState {
|
||||||
locals: EventInput[];
|
locals: EventInput[];
|
||||||
localsLoaded: { start: number; end: number }[];
|
localsLoaded: { start: number; end: number }[];
|
||||||
localsIndex: Set<string>;
|
localsIndex: Set<string>;
|
||||||
key: number;
|
key: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Context = ActionContext<CalendarLocalsState, State>;
|
type Context = ActionContext<CalendarLocalsState, State>;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: (): CalendarLocalsState => ({
|
state: (): CalendarLocalsState => ({
|
||||||
locals: [],
|
locals: [],
|
||||||
localsLoaded: [],
|
localsLoaded: [],
|
||||||
localsIndex: new Set<string>(),
|
localsIndex: new Set<string>(),
|
||||||
key: 0,
|
key: 0,
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
isLocalsLoaded:
|
isLocalsLoaded:
|
||||||
(state: CalendarLocalsState) =>
|
(state: CalendarLocalsState) =>
|
||||||
({ start, end }: { start: Date; end: Date }): boolean => {
|
({ start, end }: { start: Date; end: Date }): boolean => {
|
||||||
for (const range of state.localsLoaded) {
|
for (const range of state.localsLoaded) {
|
||||||
if (
|
if (start.getTime() === range.start && end.getTime() === range.end) {
|
||||||
start.getTime() === range.start &&
|
return true;
|
||||||
end.getTime() === range.end
|
}
|
||||||
) {
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
addLocals(state: CalendarLocalsState, ranges: CalendarLight[]) {
|
||||||
|
console.log("addLocals", ranges);
|
||||||
|
|
||||||
|
const toAdd = ranges
|
||||||
|
.map((cr) => localsToFullCalendarEvent(cr))
|
||||||
|
.filter((r) => !state.localsIndex.has(r.id));
|
||||||
|
|
||||||
|
toAdd.forEach((r) => {
|
||||||
|
state.localsIndex.add(r.id);
|
||||||
|
state.locals.push(r);
|
||||||
|
});
|
||||||
|
state.key = state.key + toAdd.length;
|
||||||
},
|
},
|
||||||
mutations: {
|
addLoaded(state: CalendarLocalsState, payload: { start: Date; end: Date }) {
|
||||||
addLocals(state: CalendarLocalsState, ranges: CalendarLight[]) {
|
state.localsLoaded.push({
|
||||||
console.log("addLocals", ranges);
|
start: payload.start.getTime(),
|
||||||
|
end: payload.end.getTime(),
|
||||||
const toAdd = ranges
|
});
|
||||||
.map((cr) => localsToFullCalendarEvent(cr))
|
|
||||||
.filter((r) => !state.localsIndex.has(r.id));
|
|
||||||
|
|
||||||
toAdd.forEach((r) => {
|
|
||||||
state.localsIndex.add(r.id);
|
|
||||||
state.locals.push(r);
|
|
||||||
});
|
|
||||||
state.key = state.key + toAdd.length;
|
|
||||||
},
|
|
||||||
addLoaded(
|
|
||||||
state: CalendarLocalsState,
|
|
||||||
payload: { start: Date; end: Date },
|
|
||||||
) {
|
|
||||||
state.localsLoaded.push({
|
|
||||||
start: payload.start.getTime(),
|
|
||||||
end: payload.end.getTime(),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
actions: {
|
},
|
||||||
fetchLocals(
|
actions: {
|
||||||
ctx: Context,
|
fetchLocals(
|
||||||
payload: { start: Date; end: Date },
|
ctx: Context,
|
||||||
): Promise<null> {
|
payload: { start: Date; end: Date },
|
||||||
const start = payload.start;
|
): Promise<null> {
|
||||||
const end = payload.end;
|
const start = payload.start;
|
||||||
|
const end = payload.end;
|
||||||
|
|
||||||
if (ctx.rootGetters["me/getMe"] === null) {
|
if (ctx.rootGetters["me/getMe"] === null) {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.getters.isLocalsLoaded({ start, end })) {
|
if (ctx.getters.isLocalsLoaded({ start, end })) {
|
||||||
return Promise.resolve(ctx.getters.getRangeSource);
|
return Promise.resolve(ctx.getters.getRangeSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.commit("addLoaded", {
|
ctx.commit("addLoaded", {
|
||||||
start: start,
|
start: start,
|
||||||
end: end,
|
end: end,
|
||||||
});
|
});
|
||||||
|
|
||||||
return fetchCalendarLocalForUser(
|
return fetchCalendarLocalForUser(ctx.rootGetters["me/getMe"], start, end)
|
||||||
ctx.rootGetters["me/getMe"],
|
.then((remotes: CalendarLight[]) => {
|
||||||
start,
|
// to be add when reactivity problem will be solve ?
|
||||||
end,
|
//ctx.commit('addRemotes', remotes);
|
||||||
)
|
const inputs = remotes
|
||||||
.then((remotes: CalendarLight[]) => {
|
.map((cr) => localsToFullCalendarEvent(cr))
|
||||||
// to be add when reactivity problem will be solve ?
|
.map((cr) => ({
|
||||||
//ctx.commit('addRemotes', remotes);
|
...cr,
|
||||||
const inputs = remotes
|
backgroundColor: COLORS[0],
|
||||||
.map((cr) => localsToFullCalendarEvent(cr))
|
textColor: "black",
|
||||||
.map((cr) => ({
|
editable: false,
|
||||||
...cr,
|
}));
|
||||||
backgroundColor: COLORS[0],
|
ctx.commit("calendarRanges/addExternals", inputs, {
|
||||||
textColor: "black",
|
root: true,
|
||||||
editable: false,
|
});
|
||||||
}));
|
return Promise.resolve(null);
|
||||||
ctx.commit("calendarRanges/addExternals", inputs, {
|
})
|
||||||
root: true,
|
.catch((e: TransportExceptionInterface) => {
|
||||||
});
|
console.error(e);
|
||||||
return Promise.resolve(null);
|
|
||||||
})
|
|
||||||
.catch((e: TransportExceptionInterface) => {
|
|
||||||
console.error(e);
|
|
||||||
|
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
});
|
});
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
} as Module<CalendarLocalsState, State>;
|
} as Module<CalendarLocalsState, State>;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { State } from "./../index";
|
import { State } from "./../index";
|
||||||
import { ActionContext, Module } from "vuex";
|
import { ActionContext, Module } from "vuex";
|
||||||
import {
|
import {
|
||||||
CalendarRange,
|
CalendarRange,
|
||||||
CalendarRangeCreate,
|
CalendarRangeCreate,
|
||||||
CalendarRangeEdit,
|
CalendarRangeEdit,
|
||||||
isEventInputCalendarRange,
|
isEventInputCalendarRange,
|
||||||
} from "../../../../types";
|
} from "../../../../types";
|
||||||
import { Location } from "../../../../../../../ChillMainBundle/Resources/public/types";
|
import { Location } from "../../../../../../../ChillMainBundle/Resources/public/types";
|
||||||
import { fetchCalendarRangeForUser } from "../../../Calendar/api";
|
import { fetchCalendarRangeForUser } from "../../../Calendar/api";
|
||||||
@@ -12,369 +12,332 @@ import { calendarRangeToFullCalendarEvent } from "../../../Calendar/store/utils"
|
|||||||
import { EventInput } from "@fullcalendar/core";
|
import { EventInput } from "@fullcalendar/core";
|
||||||
import { makeFetch } from "../../../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
|
import { makeFetch } from "../../../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
|
||||||
import {
|
import {
|
||||||
datetimeToISO,
|
datetimeToISO,
|
||||||
dateToISO,
|
dateToISO,
|
||||||
ISOToDatetime,
|
ISOToDatetime,
|
||||||
} from "../../../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
} from "../../../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
||||||
import type { EventInputCalendarRange } from "../../../../types";
|
import type { EventInputCalendarRange } from "../../../../types";
|
||||||
|
|
||||||
export interface CalendarRangesState {
|
export interface CalendarRangesState {
|
||||||
ranges: (EventInput | EventInputCalendarRange)[];
|
ranges: (EventInput | EventInputCalendarRange)[];
|
||||||
rangesLoaded: { start: number; end: number }[];
|
rangesLoaded: { start: number; end: number }[];
|
||||||
rangesIndex: Set<string>;
|
rangesIndex: Set<string>;
|
||||||
key: number;
|
key: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Context = ActionContext<CalendarRangesState, State>;
|
type Context = ActionContext<CalendarRangesState, State>;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: (): CalendarRangesState => ({
|
state: (): CalendarRangesState => ({
|
||||||
ranges: [],
|
ranges: [],
|
||||||
rangesLoaded: [],
|
rangesLoaded: [],
|
||||||
rangesIndex: new Set<string>(),
|
rangesIndex: new Set<string>(),
|
||||||
key: 0,
|
key: 0,
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
isRangeLoaded:
|
isRangeLoaded:
|
||||||
(state: CalendarRangesState) =>
|
(state: CalendarRangesState) =>
|
||||||
({ start, end }: { start: Date; end: Date }): boolean => {
|
({ start, end }: { start: Date; end: Date }): boolean => {
|
||||||
for (const range of state.rangesLoaded) {
|
for (const range of state.rangesLoaded) {
|
||||||
if (
|
if (start.getTime() === range.start && end.getTime() === range.end) {
|
||||||
start.getTime() === range.start &&
|
return true;
|
||||||
end.getTime() === range.end
|
}
|
||||||
) {
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
getRangesOnDate:
|
getRangesOnDate:
|
||||||
(state: CalendarRangesState) =>
|
(state: CalendarRangesState) =>
|
||||||
(date: Date): EventInputCalendarRange[] => {
|
(date: Date): EventInputCalendarRange[] => {
|
||||||
const founds = [];
|
const founds = [];
|
||||||
const dateStr = dateToISO(date) as string;
|
const dateStr = dateToISO(date) as string;
|
||||||
|
|
||||||
for (const range of state.ranges) {
|
for (const range of state.ranges) {
|
||||||
if (
|
if (
|
||||||
isEventInputCalendarRange(range) &&
|
isEventInputCalendarRange(range) &&
|
||||||
range.start.startsWith(dateStr)
|
range.start.startsWith(dateStr)
|
||||||
) {
|
) {
|
||||||
founds.push(range);
|
founds.push(range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return founds;
|
return founds;
|
||||||
},
|
},
|
||||||
getRangesOnWeek:
|
getRangesOnWeek:
|
||||||
(state: CalendarRangesState) =>
|
(state: CalendarRangesState) =>
|
||||||
(mondayDate: Date): EventInputCalendarRange[] => {
|
(mondayDate: Date): EventInputCalendarRange[] => {
|
||||||
const founds = [];
|
const founds = [];
|
||||||
for (const d of Array.from(Array(7).keys())) {
|
for (const d of Array.from(Array(7).keys())) {
|
||||||
const dateOfWeek = new Date(mondayDate);
|
const dateOfWeek = new Date(mondayDate);
|
||||||
dateOfWeek.setDate(mondayDate.getDate() + d);
|
dateOfWeek.setDate(mondayDate.getDate() + d);
|
||||||
const dateStr = dateToISO(dateOfWeek) as string;
|
const dateStr = dateToISO(dateOfWeek) as string;
|
||||||
for (const range of state.ranges) {
|
for (const range of state.ranges) {
|
||||||
if (
|
if (
|
||||||
isEventInputCalendarRange(range) &&
|
isEventInputCalendarRange(range) &&
|
||||||
range.start.startsWith(dateStr)
|
range.start.startsWith(dateStr)
|
||||||
) {
|
) {
|
||||||
founds.push(range);
|
founds.push(range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return founds;
|
return founds;
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
addRanges(state: CalendarRangesState, ranges: CalendarRange[]) {
|
||||||
|
const toAdd = ranges
|
||||||
|
.map((cr) => calendarRangeToFullCalendarEvent(cr))
|
||||||
|
.map((cr) => ({
|
||||||
|
...cr,
|
||||||
|
backgroundColor: "white",
|
||||||
|
borderColor: "#3788d8",
|
||||||
|
textColor: "black",
|
||||||
|
}))
|
||||||
|
.filter((r) => !state.rangesIndex.has(r.id));
|
||||||
|
|
||||||
|
toAdd.forEach((r) => {
|
||||||
|
state.rangesIndex.add(r.id);
|
||||||
|
state.ranges.push(r);
|
||||||
|
});
|
||||||
|
state.key = state.key + toAdd.length;
|
||||||
},
|
},
|
||||||
mutations: {
|
addExternals(
|
||||||
addRanges(state: CalendarRangesState, ranges: CalendarRange[]) {
|
state: CalendarRangesState,
|
||||||
const toAdd = ranges
|
externalEvents: (EventInput & { id: string })[],
|
||||||
.map((cr) => calendarRangeToFullCalendarEvent(cr))
|
) {
|
||||||
.map((cr) => ({
|
const toAdd = externalEvents.filter((r) => !state.rangesIndex.has(r.id));
|
||||||
...cr,
|
|
||||||
backgroundColor: "white",
|
|
||||||
borderColor: "#3788d8",
|
|
||||||
textColor: "black",
|
|
||||||
}))
|
|
||||||
.filter((r) => !state.rangesIndex.has(r.id));
|
|
||||||
|
|
||||||
toAdd.forEach((r) => {
|
toAdd.forEach((r) => {
|
||||||
state.rangesIndex.add(r.id);
|
state.rangesIndex.add(r.id);
|
||||||
state.ranges.push(r);
|
state.ranges.push(r);
|
||||||
});
|
});
|
||||||
state.key = state.key + toAdd.length;
|
state.key = state.key + toAdd.length;
|
||||||
},
|
|
||||||
addExternals(
|
|
||||||
state: CalendarRangesState,
|
|
||||||
externalEvents: (EventInput & { id: string })[],
|
|
||||||
) {
|
|
||||||
const toAdd = externalEvents.filter(
|
|
||||||
(r) => !state.rangesIndex.has(r.id),
|
|
||||||
);
|
|
||||||
|
|
||||||
toAdd.forEach((r) => {
|
|
||||||
state.rangesIndex.add(r.id);
|
|
||||||
state.ranges.push(r);
|
|
||||||
});
|
|
||||||
state.key = state.key + toAdd.length;
|
|
||||||
},
|
|
||||||
addLoaded(
|
|
||||||
state: CalendarRangesState,
|
|
||||||
payload: { start: Date; end: Date },
|
|
||||||
) {
|
|
||||||
state.rangesLoaded.push({
|
|
||||||
start: payload.start.getTime(),
|
|
||||||
end: payload.end.getTime(),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
addRange(state: CalendarRangesState, payload: CalendarRange) {
|
|
||||||
const asEvent = calendarRangeToFullCalendarEvent(payload);
|
|
||||||
state.ranges.push({
|
|
||||||
...asEvent,
|
|
||||||
backgroundColor: "white",
|
|
||||||
borderColor: "#3788d8",
|
|
||||||
textColor: "black",
|
|
||||||
});
|
|
||||||
state.rangesIndex.add(asEvent.id);
|
|
||||||
state.key = state.key + 1;
|
|
||||||
},
|
|
||||||
removeRange(state: CalendarRangesState, calendarRangeId: number) {
|
|
||||||
const found = state.ranges.find(
|
|
||||||
(r) =>
|
|
||||||
r.calendarRangeId === calendarRangeId && r.is === "range",
|
|
||||||
);
|
|
||||||
|
|
||||||
if (found !== undefined) {
|
|
||||||
state.ranges = state.ranges.filter(
|
|
||||||
(r) =>
|
|
||||||
!(
|
|
||||||
r.calendarRangeId === calendarRangeId &&
|
|
||||||
r.is === "range"
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (typeof found.id === "string") {
|
|
||||||
// should always be true
|
|
||||||
state.rangesIndex.delete(found.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.key = state.key + 1;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
updateRange(state: CalendarRangesState, range: CalendarRange) {
|
|
||||||
const found = state.ranges.find(
|
|
||||||
(r) => r.calendarRangeId === range.id && r.is === "range",
|
|
||||||
);
|
|
||||||
const newEvent = calendarRangeToFullCalendarEvent(range);
|
|
||||||
|
|
||||||
if (found !== undefined) {
|
|
||||||
found.start = newEvent.start;
|
|
||||||
found.end = newEvent.end;
|
|
||||||
found.locationId = range.location.id;
|
|
||||||
found.locationName = range.location.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.key = state.key + 1;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
actions: {
|
addLoaded(state: CalendarRangesState, payload: { start: Date; end: Date }) {
|
||||||
fetchRanges(
|
state.rangesLoaded.push({
|
||||||
ctx: Context,
|
start: payload.start.getTime(),
|
||||||
payload: { start: Date; end: Date },
|
end: payload.end.getTime(),
|
||||||
): Promise<null> {
|
});
|
||||||
const start = payload.start;
|
|
||||||
const end = payload.end;
|
|
||||||
|
|
||||||
if (ctx.rootGetters["me/getMe"] === null) {
|
|
||||||
return Promise.resolve(ctx.getters.getRangeSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx.getters.isRangeLoaded({ start, end })) {
|
|
||||||
return Promise.resolve(ctx.getters.getRangeSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.commit("addLoaded", {
|
|
||||||
start: start,
|
|
||||||
end: end,
|
|
||||||
});
|
|
||||||
|
|
||||||
return fetchCalendarRangeForUser(
|
|
||||||
ctx.rootGetters["me/getMe"],
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
).then((ranges: CalendarRange[]) => {
|
|
||||||
ctx.commit("addRanges", ranges);
|
|
||||||
return Promise.resolve(null);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
createRange(
|
|
||||||
ctx: Context,
|
|
||||||
{
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
location,
|
|
||||||
}: { start: Date; end: Date; location: Location },
|
|
||||||
): Promise<null> {
|
|
||||||
const url = `/api/1.0/calendar/calendar-range.json?`;
|
|
||||||
|
|
||||||
if (ctx.rootState.me.me === null) {
|
|
||||||
throw new Error("user is currently null");
|
|
||||||
}
|
|
||||||
|
|
||||||
const body = {
|
|
||||||
user: {
|
|
||||||
id: ctx.rootState.me.me.id,
|
|
||||||
type: "user",
|
|
||||||
},
|
|
||||||
startDate: {
|
|
||||||
datetime: datetimeToISO(start),
|
|
||||||
},
|
|
||||||
endDate: {
|
|
||||||
datetime: datetimeToISO(end),
|
|
||||||
},
|
|
||||||
location: {
|
|
||||||
id: location.id,
|
|
||||||
type: "location",
|
|
||||||
},
|
|
||||||
} as CalendarRangeCreate;
|
|
||||||
|
|
||||||
return makeFetch<CalendarRangeCreate, CalendarRange>(
|
|
||||||
"POST",
|
|
||||||
url,
|
|
||||||
body,
|
|
||||||
)
|
|
||||||
.then((newRange) => {
|
|
||||||
ctx.commit("addRange", newRange);
|
|
||||||
|
|
||||||
return Promise.resolve(null);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error(error);
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
deleteRange(ctx: Context, calendarRangeId: number) {
|
|
||||||
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
|
||||||
|
|
||||||
makeFetch<undefined, never>("DELETE", url).then(() => {
|
|
||||||
ctx.commit("removeRange", calendarRangeId);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
patchRangeTime(
|
|
||||||
ctx,
|
|
||||||
{
|
|
||||||
calendarRangeId,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
}: { calendarRangeId: number; start: Date; end: Date },
|
|
||||||
): Promise<null> {
|
|
||||||
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
|
||||||
const body = {
|
|
||||||
startDate: {
|
|
||||||
datetime: datetimeToISO(start),
|
|
||||||
},
|
|
||||||
endDate: {
|
|
||||||
datetime: datetimeToISO(end),
|
|
||||||
},
|
|
||||||
} as CalendarRangeEdit;
|
|
||||||
|
|
||||||
return makeFetch<CalendarRangeEdit, CalendarRange>(
|
|
||||||
"PATCH",
|
|
||||||
url,
|
|
||||||
body,
|
|
||||||
)
|
|
||||||
.then((range) => {
|
|
||||||
ctx.commit("updateRange", range);
|
|
||||||
return Promise.resolve(null);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error(error);
|
|
||||||
return Promise.resolve(null);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
patchRangeLocation(
|
|
||||||
ctx,
|
|
||||||
{
|
|
||||||
location,
|
|
||||||
calendarRangeId,
|
|
||||||
}: { location: Location; calendarRangeId: number },
|
|
||||||
): Promise<null> {
|
|
||||||
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
|
||||||
const body = {
|
|
||||||
location: {
|
|
||||||
id: location.id,
|
|
||||||
type: "location",
|
|
||||||
},
|
|
||||||
} as CalendarRangeEdit;
|
|
||||||
|
|
||||||
return makeFetch<CalendarRangeEdit, CalendarRange>(
|
|
||||||
"PATCH",
|
|
||||||
url,
|
|
||||||
body,
|
|
||||||
)
|
|
||||||
.then((range) => {
|
|
||||||
ctx.commit("updateRange", range);
|
|
||||||
return Promise.resolve(null);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error(error);
|
|
||||||
return Promise.resolve(null);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
copyFromDayToAnotherDay(
|
|
||||||
ctx,
|
|
||||||
{ from, to }: { from: Date; to: Date },
|
|
||||||
): Promise<null> {
|
|
||||||
const rangesToCopy: EventInputCalendarRange[] =
|
|
||||||
ctx.getters["getRangesOnDate"](from);
|
|
||||||
const promises = [];
|
|
||||||
|
|
||||||
for (const r of rangesToCopy) {
|
|
||||||
const start = new Date(ISOToDatetime(r.start) as Date);
|
|
||||||
start.setFullYear(
|
|
||||||
to.getFullYear(),
|
|
||||||
to.getMonth(),
|
|
||||||
to.getDate(),
|
|
||||||
);
|
|
||||||
const end = new Date(ISOToDatetime(r.end) as Date);
|
|
||||||
end.setFullYear(to.getFullYear(), to.getMonth(), to.getDate());
|
|
||||||
const location = ctx.rootGetters["locations/getLocationById"](
|
|
||||||
r.locationId,
|
|
||||||
);
|
|
||||||
|
|
||||||
promises.push(
|
|
||||||
ctx.dispatch("createRange", { start, end, location }),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.all(promises).then(() => Promise.resolve(null));
|
|
||||||
},
|
|
||||||
copyFromWeekToAnotherWeek(
|
|
||||||
ctx: Context,
|
|
||||||
{ fromMonday, toMonday }: { fromMonday: Date; toMonday: Date },
|
|
||||||
): Promise<null> {
|
|
||||||
const rangesToCopy: EventInputCalendarRange[] =
|
|
||||||
ctx.getters["getRangesOnWeek"](fromMonday);
|
|
||||||
const promises = [];
|
|
||||||
const diffTime = toMonday.getTime() - fromMonday.getTime();
|
|
||||||
for (const r of rangesToCopy) {
|
|
||||||
const start = new Date(ISOToDatetime(r.start) as Date);
|
|
||||||
const end = new Date(ISOToDatetime(r.end) as Date);
|
|
||||||
start.setTime(start.getTime() + diffTime);
|
|
||||||
end.setTime(end.getTime() + diffTime);
|
|
||||||
const location = ctx.rootGetters["locations/getLocationById"](
|
|
||||||
r.locationId,
|
|
||||||
);
|
|
||||||
|
|
||||||
promises.push(
|
|
||||||
ctx.dispatch("createRange", { start, end, location }),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.all(promises).then(() => Promise.resolve(null));
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
addRange(state: CalendarRangesState, payload: CalendarRange) {
|
||||||
|
const asEvent = calendarRangeToFullCalendarEvent(payload);
|
||||||
|
state.ranges.push({
|
||||||
|
...asEvent,
|
||||||
|
backgroundColor: "white",
|
||||||
|
borderColor: "#3788d8",
|
||||||
|
textColor: "black",
|
||||||
|
});
|
||||||
|
state.rangesIndex.add(asEvent.id);
|
||||||
|
state.key = state.key + 1;
|
||||||
|
},
|
||||||
|
removeRange(state: CalendarRangesState, calendarRangeId: number) {
|
||||||
|
const found = state.ranges.find(
|
||||||
|
(r) => r.calendarRangeId === calendarRangeId && r.is === "range",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (found !== undefined) {
|
||||||
|
state.ranges = state.ranges.filter(
|
||||||
|
(r) => !(r.calendarRangeId === calendarRangeId && r.is === "range"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (typeof found.id === "string") {
|
||||||
|
// should always be true
|
||||||
|
state.rangesIndex.delete(found.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.key = state.key + 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateRange(state: CalendarRangesState, range: CalendarRange) {
|
||||||
|
const found = state.ranges.find(
|
||||||
|
(r) => r.calendarRangeId === range.id && r.is === "range",
|
||||||
|
);
|
||||||
|
const newEvent = calendarRangeToFullCalendarEvent(range);
|
||||||
|
|
||||||
|
if (found !== undefined) {
|
||||||
|
found.start = newEvent.start;
|
||||||
|
found.end = newEvent.end;
|
||||||
|
found.locationId = range.location.id;
|
||||||
|
found.locationName = range.location.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.key = state.key + 1;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
fetchRanges(
|
||||||
|
ctx: Context,
|
||||||
|
payload: { start: Date; end: Date },
|
||||||
|
): Promise<null> {
|
||||||
|
const start = payload.start;
|
||||||
|
const end = payload.end;
|
||||||
|
|
||||||
|
if (ctx.rootGetters["me/getMe"] === null) {
|
||||||
|
return Promise.resolve(ctx.getters.getRangeSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.getters.isRangeLoaded({ start, end })) {
|
||||||
|
return Promise.resolve(ctx.getters.getRangeSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.commit("addLoaded", {
|
||||||
|
start: start,
|
||||||
|
end: end,
|
||||||
|
});
|
||||||
|
|
||||||
|
return fetchCalendarRangeForUser(
|
||||||
|
ctx.rootGetters["me/getMe"],
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
).then((ranges: CalendarRange[]) => {
|
||||||
|
ctx.commit("addRanges", ranges);
|
||||||
|
return Promise.resolve(null);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
createRange(
|
||||||
|
ctx: Context,
|
||||||
|
{ start, end, location }: { start: Date; end: Date; location: Location },
|
||||||
|
): Promise<null> {
|
||||||
|
const url = `/api/1.0/calendar/calendar-range.json?`;
|
||||||
|
|
||||||
|
if (ctx.rootState.me.me === null) {
|
||||||
|
throw new Error("user is currently null");
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
user: {
|
||||||
|
id: ctx.rootState.me.me.id,
|
||||||
|
type: "user",
|
||||||
|
},
|
||||||
|
startDate: {
|
||||||
|
datetime: datetimeToISO(start),
|
||||||
|
},
|
||||||
|
endDate: {
|
||||||
|
datetime: datetimeToISO(end),
|
||||||
|
},
|
||||||
|
location: {
|
||||||
|
id: location.id,
|
||||||
|
type: "location",
|
||||||
|
},
|
||||||
|
} as CalendarRangeCreate;
|
||||||
|
|
||||||
|
return makeFetch<CalendarRangeCreate, CalendarRange>("POST", url, body)
|
||||||
|
.then((newRange) => {
|
||||||
|
ctx.commit("addRange", newRange);
|
||||||
|
|
||||||
|
return Promise.resolve(null);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteRange(ctx: Context, calendarRangeId: number) {
|
||||||
|
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
||||||
|
|
||||||
|
makeFetch<undefined, never>("DELETE", url).then(() => {
|
||||||
|
ctx.commit("removeRange", calendarRangeId);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
patchRangeTime(
|
||||||
|
ctx,
|
||||||
|
{
|
||||||
|
calendarRangeId,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
}: { calendarRangeId: number; start: Date; end: Date },
|
||||||
|
): Promise<null> {
|
||||||
|
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
||||||
|
const body = {
|
||||||
|
startDate: {
|
||||||
|
datetime: datetimeToISO(start),
|
||||||
|
},
|
||||||
|
endDate: {
|
||||||
|
datetime: datetimeToISO(end),
|
||||||
|
},
|
||||||
|
} as CalendarRangeEdit;
|
||||||
|
|
||||||
|
return makeFetch<CalendarRangeEdit, CalendarRange>("PATCH", url, body)
|
||||||
|
.then((range) => {
|
||||||
|
ctx.commit("updateRange", range);
|
||||||
|
return Promise.resolve(null);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
return Promise.resolve(null);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
patchRangeLocation(
|
||||||
|
ctx,
|
||||||
|
{
|
||||||
|
location,
|
||||||
|
calendarRangeId,
|
||||||
|
}: { location: Location; calendarRangeId: number },
|
||||||
|
): Promise<null> {
|
||||||
|
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
||||||
|
const body = {
|
||||||
|
location: {
|
||||||
|
id: location.id,
|
||||||
|
type: "location",
|
||||||
|
},
|
||||||
|
} as CalendarRangeEdit;
|
||||||
|
|
||||||
|
return makeFetch<CalendarRangeEdit, CalendarRange>("PATCH", url, body)
|
||||||
|
.then((range) => {
|
||||||
|
ctx.commit("updateRange", range);
|
||||||
|
return Promise.resolve(null);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
return Promise.resolve(null);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
copyFromDayToAnotherDay(
|
||||||
|
ctx,
|
||||||
|
{ from, to }: { from: Date; to: Date },
|
||||||
|
): Promise<null> {
|
||||||
|
const rangesToCopy: EventInputCalendarRange[] =
|
||||||
|
ctx.getters["getRangesOnDate"](from);
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
|
for (const r of rangesToCopy) {
|
||||||
|
const start = new Date(ISOToDatetime(r.start) as Date);
|
||||||
|
start.setFullYear(to.getFullYear(), to.getMonth(), to.getDate());
|
||||||
|
const end = new Date(ISOToDatetime(r.end) as Date);
|
||||||
|
end.setFullYear(to.getFullYear(), to.getMonth(), to.getDate());
|
||||||
|
const location = ctx.rootGetters["locations/getLocationById"](
|
||||||
|
r.locationId,
|
||||||
|
);
|
||||||
|
|
||||||
|
promises.push(ctx.dispatch("createRange", { start, end, location }));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(promises).then(() => Promise.resolve(null));
|
||||||
|
},
|
||||||
|
copyFromWeekToAnotherWeek(
|
||||||
|
ctx: Context,
|
||||||
|
{ fromMonday, toMonday }: { fromMonday: Date; toMonday: Date },
|
||||||
|
): Promise<null> {
|
||||||
|
const rangesToCopy: EventInputCalendarRange[] =
|
||||||
|
ctx.getters["getRangesOnWeek"](fromMonday);
|
||||||
|
const promises = [];
|
||||||
|
const diffTime = toMonday.getTime() - fromMonday.getTime();
|
||||||
|
for (const r of rangesToCopy) {
|
||||||
|
const start = new Date(ISOToDatetime(r.start) as Date);
|
||||||
|
const end = new Date(ISOToDatetime(r.end) as Date);
|
||||||
|
start.setTime(start.getTime() + diffTime);
|
||||||
|
end.setTime(end.getTime() + diffTime);
|
||||||
|
const location = ctx.rootGetters["locations/getLocationById"](
|
||||||
|
r.locationId,
|
||||||
|
);
|
||||||
|
|
||||||
|
promises.push(ctx.dispatch("createRange", { start, end, location }));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(promises).then(() => Promise.resolve(null));
|
||||||
|
},
|
||||||
|
},
|
||||||
} as Module<CalendarRangesState, State>;
|
} as Module<CalendarRangesState, State>;
|
||||||
|
|||||||
@@ -8,109 +8,102 @@ import { TransportExceptionInterface } from "../../../../../../../ChillMainBundl
|
|||||||
import { COLORS } from "../../../Calendar/const";
|
import { COLORS } from "../../../Calendar/const";
|
||||||
|
|
||||||
export interface CalendarRemotesState {
|
export interface CalendarRemotesState {
|
||||||
remotes: EventInput[];
|
remotes: EventInput[];
|
||||||
remotesLoaded: { start: number; end: number }[];
|
remotesLoaded: { start: number; end: number }[];
|
||||||
remotesIndex: Set<string>;
|
remotesIndex: Set<string>;
|
||||||
key: number;
|
key: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Context = ActionContext<CalendarRemotesState, State>;
|
type Context = ActionContext<CalendarRemotesState, State>;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: (): CalendarRemotesState => ({
|
state: (): CalendarRemotesState => ({
|
||||||
remotes: [],
|
remotes: [],
|
||||||
remotesLoaded: [],
|
remotesLoaded: [],
|
||||||
remotesIndex: new Set<string>(),
|
remotesIndex: new Set<string>(),
|
||||||
key: 0,
|
key: 0,
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
isRemotesLoaded:
|
isRemotesLoaded:
|
||||||
(state: CalendarRemotesState) =>
|
(state: CalendarRemotesState) =>
|
||||||
({ start, end }: { start: Date; end: Date }): boolean => {
|
({ start, end }: { start: Date; end: Date }): boolean => {
|
||||||
for (const range of state.remotesLoaded) {
|
for (const range of state.remotesLoaded) {
|
||||||
if (
|
if (start.getTime() === range.start && end.getTime() === range.end) {
|
||||||
start.getTime() === range.start &&
|
return true;
|
||||||
end.getTime() === range.end
|
}
|
||||||
) {
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
addRemotes(state: CalendarRemotesState, ranges: CalendarRemote[]) {
|
||||||
|
console.log("addRemotes", ranges);
|
||||||
|
|
||||||
|
const toAdd = ranges
|
||||||
|
.map((cr) => remoteToFullCalendarEvent(cr))
|
||||||
|
.filter((r) => !state.remotesIndex.has(r.id));
|
||||||
|
|
||||||
|
toAdd.forEach((r) => {
|
||||||
|
state.remotesIndex.add(r.id);
|
||||||
|
state.remotes.push(r);
|
||||||
|
});
|
||||||
|
state.key = state.key + toAdd.length;
|
||||||
},
|
},
|
||||||
mutations: {
|
addLoaded(
|
||||||
addRemotes(state: CalendarRemotesState, ranges: CalendarRemote[]) {
|
state: CalendarRemotesState,
|
||||||
console.log("addRemotes", ranges);
|
payload: { start: Date; end: Date },
|
||||||
|
) {
|
||||||
const toAdd = ranges
|
state.remotesLoaded.push({
|
||||||
.map((cr) => remoteToFullCalendarEvent(cr))
|
start: payload.start.getTime(),
|
||||||
.filter((r) => !state.remotesIndex.has(r.id));
|
end: payload.end.getTime(),
|
||||||
|
});
|
||||||
toAdd.forEach((r) => {
|
|
||||||
state.remotesIndex.add(r.id);
|
|
||||||
state.remotes.push(r);
|
|
||||||
});
|
|
||||||
state.key = state.key + toAdd.length;
|
|
||||||
},
|
|
||||||
addLoaded(
|
|
||||||
state: CalendarRemotesState,
|
|
||||||
payload: { start: Date; end: Date },
|
|
||||||
) {
|
|
||||||
state.remotesLoaded.push({
|
|
||||||
start: payload.start.getTime(),
|
|
||||||
end: payload.end.getTime(),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
actions: {
|
},
|
||||||
fetchRemotes(
|
actions: {
|
||||||
ctx: Context,
|
fetchRemotes(
|
||||||
payload: { start: Date; end: Date },
|
ctx: Context,
|
||||||
): Promise<null> {
|
payload: { start: Date; end: Date },
|
||||||
const start = payload.start;
|
): Promise<null> {
|
||||||
const end = payload.end;
|
const start = payload.start;
|
||||||
|
const end = payload.end;
|
||||||
|
|
||||||
if (ctx.rootGetters["me/getMe"] === null) {
|
if (ctx.rootGetters["me/getMe"] === null) {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.getters.isRemotesLoaded({ start, end })) {
|
if (ctx.getters.isRemotesLoaded({ start, end })) {
|
||||||
return Promise.resolve(ctx.getters.getRangeSource);
|
return Promise.resolve(ctx.getters.getRangeSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.commit("addLoaded", {
|
ctx.commit("addLoaded", {
|
||||||
start: start,
|
start: start,
|
||||||
end: end,
|
end: end,
|
||||||
});
|
});
|
||||||
|
|
||||||
return fetchCalendarRemoteForUser(
|
return fetchCalendarRemoteForUser(ctx.rootGetters["me/getMe"], start, end)
|
||||||
ctx.rootGetters["me/getMe"],
|
.then((remotes: CalendarRemote[]) => {
|
||||||
start,
|
// to be add when reactivity problem will be solve ?
|
||||||
end,
|
//ctx.commit('addRemotes', remotes);
|
||||||
)
|
const inputs = remotes
|
||||||
.then((remotes: CalendarRemote[]) => {
|
.map((cr) => remoteToFullCalendarEvent(cr))
|
||||||
// to be add when reactivity problem will be solve ?
|
.map((cr) => ({
|
||||||
//ctx.commit('addRemotes', remotes);
|
...cr,
|
||||||
const inputs = remotes
|
backgroundColor: COLORS[0],
|
||||||
.map((cr) => remoteToFullCalendarEvent(cr))
|
textColor: "black",
|
||||||
.map((cr) => ({
|
editable: false,
|
||||||
...cr,
|
}));
|
||||||
backgroundColor: COLORS[0],
|
ctx.commit("calendarRanges/addExternals", inputs, {
|
||||||
textColor: "black",
|
root: true,
|
||||||
editable: false,
|
});
|
||||||
}));
|
return Promise.resolve(null);
|
||||||
ctx.commit("calendarRanges/addExternals", inputs, {
|
})
|
||||||
root: true,
|
.catch((e: TransportExceptionInterface) => {
|
||||||
});
|
console.error(e);
|
||||||
return Promise.resolve(null);
|
|
||||||
})
|
|
||||||
.catch((e: TransportExceptionInterface) => {
|
|
||||||
console.error(e);
|
|
||||||
|
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
});
|
});
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
} as Module<CalendarRemotesState, State>;
|
} as Module<CalendarRemotesState, State>;
|
||||||
|
|||||||
@@ -2,77 +2,77 @@ import { State } from "./../index";
|
|||||||
import { ActionContext } from "vuex";
|
import { ActionContext } from "vuex";
|
||||||
|
|
||||||
export interface FullCalendarState {
|
export interface FullCalendarState {
|
||||||
currentView: {
|
currentView: {
|
||||||
start: Date | null;
|
start: Date | null;
|
||||||
end: Date | null;
|
end: Date | null;
|
||||||
};
|
};
|
||||||
key: number;
|
key: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Context = ActionContext<FullCalendarState, State>;
|
type Context = ActionContext<FullCalendarState, State>;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: (): FullCalendarState => ({
|
state: (): FullCalendarState => ({
|
||||||
currentView: {
|
currentView: {
|
||||||
start: null,
|
start: null,
|
||||||
end: null,
|
end: null,
|
||||||
},
|
|
||||||
key: 0,
|
|
||||||
}),
|
|
||||||
mutations: {
|
|
||||||
setCurrentDatesView: function (
|
|
||||||
state: FullCalendarState,
|
|
||||||
payload: { start: Date; end: Date },
|
|
||||||
): void {
|
|
||||||
state.currentView.start = payload.start;
|
|
||||||
state.currentView.end = payload.end;
|
|
||||||
},
|
|
||||||
increaseKey: function (state: FullCalendarState): void {
|
|
||||||
state.key = state.key + 1;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
actions: {
|
key: 0,
|
||||||
setCurrentDatesView(
|
}),
|
||||||
ctx: Context,
|
mutations: {
|
||||||
{ start, end }: { start: Date | null; end: Date | null },
|
setCurrentDatesView: function (
|
||||||
): Promise<null> {
|
state: FullCalendarState,
|
||||||
console.log("dispatch setCurrentDatesView", { start, end });
|
payload: { start: Date; end: Date },
|
||||||
|
): void {
|
||||||
if (
|
state.currentView.start = payload.start;
|
||||||
ctx.state.currentView.start !== start ||
|
state.currentView.end = payload.end;
|
||||||
ctx.state.currentView.end !== end
|
|
||||||
) {
|
|
||||||
ctx.commit("setCurrentDatesView", { start, end });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start !== null && end !== null) {
|
|
||||||
return Promise.all([
|
|
||||||
ctx
|
|
||||||
.dispatch(
|
|
||||||
"calendarRanges/fetchRanges",
|
|
||||||
{ start, end },
|
|
||||||
{ root: true },
|
|
||||||
)
|
|
||||||
.then((_) => Promise.resolve(null)),
|
|
||||||
ctx
|
|
||||||
.dispatch(
|
|
||||||
"calendarRemotes/fetchRemotes",
|
|
||||||
{ start, end },
|
|
||||||
{ root: true },
|
|
||||||
)
|
|
||||||
.then((_) => Promise.resolve(null)),
|
|
||||||
ctx
|
|
||||||
.dispatch(
|
|
||||||
"calendarLocals/fetchLocals",
|
|
||||||
{ start, end },
|
|
||||||
{ root: true },
|
|
||||||
)
|
|
||||||
.then((_) => Promise.resolve(null)),
|
|
||||||
]).then((_) => Promise.resolve(null));
|
|
||||||
} else {
|
|
||||||
return Promise.resolve(null);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
increaseKey: function (state: FullCalendarState): void {
|
||||||
|
state.key = state.key + 1;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
setCurrentDatesView(
|
||||||
|
ctx: Context,
|
||||||
|
{ start, end }: { start: Date | null; end: Date | null },
|
||||||
|
): Promise<null> {
|
||||||
|
console.log("dispatch setCurrentDatesView", { start, end });
|
||||||
|
|
||||||
|
if (
|
||||||
|
ctx.state.currentView.start !== start ||
|
||||||
|
ctx.state.currentView.end !== end
|
||||||
|
) {
|
||||||
|
ctx.commit("setCurrentDatesView", { start, end });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start !== null && end !== null) {
|
||||||
|
return Promise.all([
|
||||||
|
ctx
|
||||||
|
.dispatch(
|
||||||
|
"calendarRanges/fetchRanges",
|
||||||
|
{ start, end },
|
||||||
|
{ root: true },
|
||||||
|
)
|
||||||
|
.then((_) => Promise.resolve(null)),
|
||||||
|
ctx
|
||||||
|
.dispatch(
|
||||||
|
"calendarRemotes/fetchRemotes",
|
||||||
|
{ start, end },
|
||||||
|
{ root: true },
|
||||||
|
)
|
||||||
|
.then((_) => Promise.resolve(null)),
|
||||||
|
ctx
|
||||||
|
.dispatch(
|
||||||
|
"calendarLocals/fetchLocals",
|
||||||
|
{ start, end },
|
||||||
|
{ root: true },
|
||||||
|
)
|
||||||
|
.then((_) => Promise.resolve(null)),
|
||||||
|
]).then((_) => Promise.resolve(null));
|
||||||
|
} else {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,61 +5,61 @@ import { getLocations } from "../../../../../../../ChillMainBundle/Resources/pub
|
|||||||
import { whereami } from "../../../../../../../ChillMainBundle/Resources/public/lib/api/user";
|
import { whereami } from "../../../../../../../ChillMainBundle/Resources/public/lib/api/user";
|
||||||
|
|
||||||
export interface LocationState {
|
export interface LocationState {
|
||||||
locations: Location[];
|
locations: Location[];
|
||||||
locationPicked: Location | null;
|
locationPicked: Location | null;
|
||||||
currentLocation: Location | null;
|
currentLocation: Location | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: (): LocationState => {
|
state: (): LocationState => {
|
||||||
return {
|
return {
|
||||||
locations: [],
|
locations: [],
|
||||||
locationPicked: null,
|
locationPicked: null,
|
||||||
currentLocation: null,
|
currentLocation: null,
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
getLocationById:
|
||||||
|
(state) =>
|
||||||
|
(id: number): Location | undefined => {
|
||||||
|
return state.locations.find((l) => l.id === id);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
setLocations(state, locations): void {
|
||||||
|
state.locations = locations;
|
||||||
},
|
},
|
||||||
getters: {
|
setLocationPicked(state, location: Location | null): void {
|
||||||
getLocationById:
|
if (null === location) {
|
||||||
(state) =>
|
state.locationPicked = null;
|
||||||
(id: number): Location | undefined => {
|
return;
|
||||||
return state.locations.find((l) => l.id === id);
|
}
|
||||||
},
|
|
||||||
},
|
|
||||||
mutations: {
|
|
||||||
setLocations(state, locations): void {
|
|
||||||
state.locations = locations;
|
|
||||||
},
|
|
||||||
setLocationPicked(state, location: Location | null): void {
|
|
||||||
if (null === location) {
|
|
||||||
state.locationPicked = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.locationPicked =
|
state.locationPicked =
|
||||||
state.locations.find((l) => l.id === location.id) || null;
|
state.locations.find((l) => l.id === location.id) || null;
|
||||||
},
|
},
|
||||||
setCurrentLocation(state, location: Location | null): void {
|
setCurrentLocation(state, location: Location | null): void {
|
||||||
if (null === location) {
|
if (null === location) {
|
||||||
state.currentLocation = null;
|
state.currentLocation = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.currentLocation =
|
state.currentLocation =
|
||||||
state.locations.find((l) => l.id === location.id) || null;
|
state.locations.find((l) => l.id === location.id) || null;
|
||||||
},
|
|
||||||
},
|
},
|
||||||
actions: {
|
},
|
||||||
getLocations(ctx): Promise<void> {
|
actions: {
|
||||||
return getLocations().then((locations) => {
|
getLocations(ctx): Promise<void> {
|
||||||
ctx.commit("setLocations", locations);
|
return getLocations().then((locations) => {
|
||||||
return Promise.resolve();
|
ctx.commit("setLocations", locations);
|
||||||
});
|
return Promise.resolve();
|
||||||
},
|
});
|
||||||
getCurrentLocation(ctx): Promise<void> {
|
|
||||||
return whereami().then((location) => {
|
|
||||||
ctx.commit("setCurrentLocation", location);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
getCurrentLocation(ctx): Promise<void> {
|
||||||
|
return whereami().then((location) => {
|
||||||
|
ctx.commit("setCurrentLocation", location);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
} as Module<LocationState, State>;
|
} as Module<LocationState, State>;
|
||||||
|
|||||||
@@ -3,24 +3,24 @@ import { User } from "../../../../../../../ChillMainBundle/Resources/public/type
|
|||||||
import { ActionContext } from "vuex";
|
import { ActionContext } from "vuex";
|
||||||
|
|
||||||
export interface MeState {
|
export interface MeState {
|
||||||
me: User | null;
|
me: User | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Context = ActionContext<MeState, State>;
|
type Context = ActionContext<MeState, State>;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: (): MeState => ({
|
state: (): MeState => ({
|
||||||
me: null,
|
me: null,
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
getMe: function (state: MeState): User | null {
|
getMe: function (state: MeState): User | null {
|
||||||
return state.me;
|
return state.me;
|
||||||
},
|
|
||||||
},
|
},
|
||||||
mutations: {
|
},
|
||||||
setWhoAmi(state: MeState, me: User) {
|
mutations: {
|
||||||
state.me = me;
|
setWhoAmi(state: MeState, me: User) {
|
||||||
},
|
state.me = me;
|
||||||
},
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h2 class="chill-red">
|
<h2 class="chill-red">
|
||||||
{{ $t("choose_your_calendar_user") }}
|
{{ $t("choose_your_calendar_user") }}
|
||||||
</h2>
|
</h2>
|
||||||
<VueMultiselect
|
<VueMultiselect
|
||||||
name="field"
|
name="field"
|
||||||
id="calendarUserSelector"
|
id="calendarUserSelector"
|
||||||
v-model="value"
|
v-model="value"
|
||||||
track-by="id"
|
track-by="id"
|
||||||
label="value"
|
label="value"
|
||||||
:custom-label="transName"
|
:custom-label="transName"
|
||||||
:placeholder="$t('select_user')"
|
:placeholder="$t('select_user')"
|
||||||
:multiple="true"
|
:multiple="true"
|
||||||
:close-on-select="false"
|
:close-on-select="false"
|
||||||
:allow-empty="true"
|
:allow-empty="true"
|
||||||
:model-value="value"
|
:model-value="value"
|
||||||
:select-label="$t('multiselect.select_label')"
|
:select-label="$t('multiselect.select_label')"
|
||||||
:deselect-label="$t('multiselect.deselect_label')"
|
:deselect-label="$t('multiselect.deselect_label')"
|
||||||
:selected-label="$t('multiselect.selected_label')"
|
:selected-label="$t('multiselect.selected_label')"
|
||||||
@select="selectUsers"
|
@select="selectUsers"
|
||||||
@remove="unSelectUsers"
|
@remove="unSelectUsers"
|
||||||
@close="coloriseSelectedValues"
|
@close="coloriseSelectedValues"
|
||||||
:options="options"
|
:options="options"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="myCalendar"
|
id="myCalendar"
|
||||||
class="form-check-input"
|
class="form-check-input"
|
||||||
v-model="showMyCalendarWidget"
|
v-model="showMyCalendarWidget"
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label" for="myCalendar">{{
|
<label class="form-check-label" for="myCalendar">{{
|
||||||
$t("show_my_calendar")
|
$t("show_my_calendar")
|
||||||
}}</label>
|
}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="weekends"
|
id="weekends"
|
||||||
class="form-check-input"
|
class="form-check-input"
|
||||||
@click="toggleWeekends"
|
@click="toggleWeekends"
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label" for="weekends">{{
|
<label class="form-check-label" for="weekends">{{
|
||||||
$t("show_weekends")
|
$t("show_weekends")
|
||||||
}}</label>
|
}}</label>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { fetchCalendarRanges, fetchCalendar } from "../../_api/api";
|
import { fetchCalendarRanges, fetchCalendar } from "../../_api/api";
|
||||||
@@ -53,206 +53,183 @@ import VueMultiselect from "vue-multiselect";
|
|||||||
import { whoami } from "ChillPersonAssets/vuejs/AccompanyingCourse/api";
|
import { whoami } from "ChillPersonAssets/vuejs/AccompanyingCourse/api";
|
||||||
|
|
||||||
const COLORS = [
|
const COLORS = [
|
||||||
/* from https://colorbrewer2.org/#type=qualitative&scheme=Set3&n=12 */
|
/* from https://colorbrewer2.org/#type=qualitative&scheme=Set3&n=12 */
|
||||||
"#8dd3c7",
|
"#8dd3c7",
|
||||||
"#ffffb3",
|
"#ffffb3",
|
||||||
"#bebada",
|
"#bebada",
|
||||||
"#fb8072",
|
"#fb8072",
|
||||||
"#80b1d3",
|
"#80b1d3",
|
||||||
"#fdb462",
|
"#fdb462",
|
||||||
"#b3de69",
|
"#b3de69",
|
||||||
"#fccde5",
|
"#fccde5",
|
||||||
"#d9d9d9",
|
"#d9d9d9",
|
||||||
"#bc80bd",
|
"#bc80bd",
|
||||||
"#ccebc5",
|
"#ccebc5",
|
||||||
"#ffed6f",
|
"#ffed6f",
|
||||||
];
|
];
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "CalendarUserSelector",
|
name: "CalendarUserSelector",
|
||||||
components: { VueMultiselect },
|
components: { VueMultiselect },
|
||||||
props: [
|
props: [
|
||||||
"users",
|
"users",
|
||||||
"updateEventsSource",
|
"updateEventsSource",
|
||||||
"calendarEvents",
|
"calendarEvents",
|
||||||
"showMyCalendar",
|
"showMyCalendar",
|
||||||
"toggleMyCalendar",
|
"toggleMyCalendar",
|
||||||
"toggleWeekends",
|
"toggleWeekends",
|
||||||
],
|
],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
errorMsg: [],
|
errorMsg: [],
|
||||||
value: [],
|
value: [],
|
||||||
options: [],
|
options: [],
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
showMyCalendarWidget: {
|
||||||
|
set(value) {
|
||||||
|
this.toggleMyCalendar(value);
|
||||||
|
this.updateEventsSource();
|
||||||
|
},
|
||||||
|
get() {
|
||||||
|
return this.showMyCalendar;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
},
|
||||||
showMyCalendarWidget: {
|
methods: {
|
||||||
set(value) {
|
init() {
|
||||||
this.toggleMyCalendar(value);
|
this.fetchData();
|
||||||
this.updateEventsSource();
|
|
||||||
},
|
|
||||||
get() {
|
|
||||||
return this.showMyCalendar;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
fetchData() {
|
||||||
init() {
|
fetchCalendarRanges()
|
||||||
this.fetchData();
|
.then(
|
||||||
},
|
(calendarRanges) =>
|
||||||
fetchData() {
|
new Promise((resolve, reject) => {
|
||||||
fetchCalendarRanges()
|
let results = calendarRanges.results;
|
||||||
.then(
|
|
||||||
(calendarRanges) =>
|
|
||||||
new Promise((resolve, reject) => {
|
|
||||||
let results = calendarRanges.results;
|
|
||||||
|
|
||||||
let users = [];
|
let users = [];
|
||||||
|
|
||||||
results.forEach((i) => {
|
results.forEach((i) => {
|
||||||
if (!users.some((j) => i.user.id === j.id)) {
|
if (!users.some((j) => i.user.id === j.id)) {
|
||||||
let ratio = Math.floor(
|
let ratio = Math.floor(users.length / COLORS.length);
|
||||||
users.length / COLORS.length,
|
let colorIndex = users.length - ratio * COLORS.length;
|
||||||
);
|
users.push({
|
||||||
let colorIndex =
|
id: i.user.id,
|
||||||
users.length - ratio * COLORS.length;
|
username: i.user.username,
|
||||||
users.push({
|
color: COLORS[colorIndex],
|
||||||
id: i.user.id,
|
});
|
||||||
username: i.user.username,
|
|
||||||
color: COLORS[colorIndex],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let calendarEvents = [];
|
|
||||||
users.forEach((u) => {
|
|
||||||
let arr = results
|
|
||||||
.filter((i) => i.user.id === u.id)
|
|
||||||
.map((i) => ({
|
|
||||||
start: i.startDate.datetime,
|
|
||||||
end: i.endDate.datetime,
|
|
||||||
calendarRangeId: i.id,
|
|
||||||
sourceColor: u.color,
|
|
||||||
//display: 'background' // can be an option for the disponibility
|
|
||||||
}));
|
|
||||||
calendarEvents.push({
|
|
||||||
events: arr,
|
|
||||||
color: u.color,
|
|
||||||
textColor: "#444444",
|
|
||||||
editable: false,
|
|
||||||
id: u.id,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.users.loaded = users;
|
|
||||||
this.options = users;
|
|
||||||
|
|
||||||
this.calendarEvents.loaded = calendarEvents;
|
|
||||||
whoami().then(
|
|
||||||
(me) =>
|
|
||||||
new Promise((resolve, reject) => {
|
|
||||||
this.users.logged = me;
|
|
||||||
let currentUser = users.find(
|
|
||||||
(u) => u.id === me.id,
|
|
||||||
);
|
|
||||||
this.value = currentUser;
|
|
||||||
|
|
||||||
fetchCalendar(currentUser.id).then(
|
|
||||||
(calendar) =>
|
|
||||||
new Promise(
|
|
||||||
(resolve, reject) => {
|
|
||||||
let results =
|
|
||||||
calendar.results;
|
|
||||||
let events =
|
|
||||||
results.map(
|
|
||||||
(i) => ({
|
|
||||||
start: i
|
|
||||||
.startDate
|
|
||||||
.datetime,
|
|
||||||
end: i
|
|
||||||
.endDate
|
|
||||||
.datetime,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
let calendarEventsCurrentUser =
|
|
||||||
{
|
|
||||||
events: events,
|
|
||||||
color: "darkblue",
|
|
||||||
id: 1000,
|
|
||||||
editable: false,
|
|
||||||
};
|
|
||||||
this.calendarEvents.user =
|
|
||||||
calendarEventsCurrentUser;
|
|
||||||
|
|
||||||
this.selectUsers(
|
|
||||||
currentUser,
|
|
||||||
);
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.catch((error) => {
|
|
||||||
this.errorMsg.push(error.message);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
transName(value) {
|
|
||||||
return `${value.username}`;
|
|
||||||
},
|
|
||||||
coloriseSelectedValues() {
|
|
||||||
let tags = document.querySelectorAll(
|
|
||||||
"div.multiselect__tags-wrap",
|
|
||||||
)[0];
|
|
||||||
|
|
||||||
if (tags.hasChildNodes()) {
|
|
||||||
let children = tags.childNodes;
|
|
||||||
for (let i = 0; i < children.length; i++) {
|
|
||||||
let child = children[i];
|
|
||||||
if (child.nodeType === Node.ELEMENT_NODE) {
|
|
||||||
this.users.selected.forEach((u) => {
|
|
||||||
if (child.hasChildNodes()) {
|
|
||||||
if (child.firstChild.innerText == u.username) {
|
|
||||||
child.style.background = u.color;
|
|
||||||
child.firstChild.style.color = "#444444";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
},
|
|
||||||
selectEvents() {
|
let calendarEvents = [];
|
||||||
let selectedUsersId = this.users.selected.map((a) => a.id);
|
users.forEach((u) => {
|
||||||
this.calendarEvents.selected = this.calendarEvents.loaded.filter(
|
let arr = results
|
||||||
(a) => selectedUsersId.includes(a.id),
|
.filter((i) => i.user.id === u.id)
|
||||||
);
|
.map((i) => ({
|
||||||
},
|
start: i.startDate.datetime,
|
||||||
selectUsers(value) {
|
end: i.endDate.datetime,
|
||||||
this.users.selected.push(value);
|
calendarRangeId: i.id,
|
||||||
this.coloriseSelectedValues();
|
sourceColor: u.color,
|
||||||
this.selectEvents();
|
//display: 'background' // can be an option for the disponibility
|
||||||
this.updateEventsSource();
|
}));
|
||||||
},
|
calendarEvents.push({
|
||||||
unSelectUsers(value) {
|
events: arr,
|
||||||
this.users.selected = this.users.selected.filter(
|
color: u.color,
|
||||||
(a) => a.id != value.id,
|
textColor: "#444444",
|
||||||
);
|
editable: false,
|
||||||
this.selectEvents();
|
id: u.id,
|
||||||
this.updateEventsSource();
|
});
|
||||||
},
|
});
|
||||||
|
|
||||||
|
this.users.loaded = users;
|
||||||
|
this.options = users;
|
||||||
|
|
||||||
|
this.calendarEvents.loaded = calendarEvents;
|
||||||
|
whoami().then(
|
||||||
|
(me) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
this.users.logged = me;
|
||||||
|
let currentUser = users.find((u) => u.id === me.id);
|
||||||
|
this.value = currentUser;
|
||||||
|
|
||||||
|
fetchCalendar(currentUser.id).then(
|
||||||
|
(calendar) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
let results = calendar.results;
|
||||||
|
let events = results.map((i) => ({
|
||||||
|
start: i.startDate.datetime,
|
||||||
|
end: i.endDate.datetime,
|
||||||
|
}));
|
||||||
|
let calendarEventsCurrentUser = {
|
||||||
|
events: events,
|
||||||
|
color: "darkblue",
|
||||||
|
id: 1000,
|
||||||
|
editable: false,
|
||||||
|
};
|
||||||
|
this.calendarEvents.user = calendarEventsCurrentUser;
|
||||||
|
|
||||||
|
this.selectUsers(currentUser);
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.catch((error) => {
|
||||||
|
this.errorMsg.push(error.message);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
mounted() {
|
transName(value) {
|
||||||
this.init();
|
return `${value.username}`;
|
||||||
},
|
},
|
||||||
|
coloriseSelectedValues() {
|
||||||
|
let tags = document.querySelectorAll("div.multiselect__tags-wrap")[0];
|
||||||
|
|
||||||
|
if (tags.hasChildNodes()) {
|
||||||
|
let children = tags.childNodes;
|
||||||
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
let child = children[i];
|
||||||
|
if (child.nodeType === Node.ELEMENT_NODE) {
|
||||||
|
this.users.selected.forEach((u) => {
|
||||||
|
if (child.hasChildNodes()) {
|
||||||
|
if (child.firstChild.innerText == u.username) {
|
||||||
|
child.style.background = u.color;
|
||||||
|
child.firstChild.style.color = "#444444";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectEvents() {
|
||||||
|
let selectedUsersId = this.users.selected.map((a) => a.id);
|
||||||
|
this.calendarEvents.selected = this.calendarEvents.loaded.filter((a) =>
|
||||||
|
selectedUsersId.includes(a.id),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
selectUsers(value) {
|
||||||
|
this.users.selected.push(value);
|
||||||
|
this.coloriseSelectedValues();
|
||||||
|
this.selectEvents();
|
||||||
|
this.updateEventsSource();
|
||||||
|
},
|
||||||
|
unSelectUsers(value) {
|
||||||
|
this.users.selected = this.users.selected.filter((a) => a.id != value.id);
|
||||||
|
this.selectEvents();
|
||||||
|
this.updateEventsSource();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
{# list used in context of person or accompanyingPeriod #}
|
{# list used in context of person, accompanyingPeriod or user #}
|
||||||
|
|
||||||
{% if calendarItems|length > 0 %}
|
<div class="item-bloc">
|
||||||
<div class="flex-table list-records context-accompanyingCourse">
|
<div class="item-row main">
|
||||||
|
<div class="item-col">
|
||||||
{% for calendar in calendarItems %}
|
<div class="wrap-header">
|
||||||
|
<div class="wl-row">
|
||||||
<div class="item-bloc">
|
{% if calendar.status == 'canceled' %}
|
||||||
<div class="item-row main">
|
<div class="badge rounded-pill bg-danger">
|
||||||
<div class="item-col">
|
<span>{{ 'chill_calendar.canceled'|trans }}: </span>
|
||||||
<div class="wrap-header">
|
<span>{{ calendar.cancelReason.name|localize_translatable_string }}</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
<div class="wl-row">
|
<div class="wl-row">
|
||||||
<div class="wl-col title">
|
<div class="wl-col title">
|
||||||
<p class="date-label">
|
<p class="date-label">
|
||||||
|
{% if calendar.status == 'canceled' %}
|
||||||
|
<del>
|
||||||
|
{% endif %}
|
||||||
{% if context == 'person' and calendar.context == 'accompanying_period' %}
|
{% if context == 'person' and calendar.context == 'accompanying_period' %}
|
||||||
<a href="{{ chill_path_add_return_path('chill_person_accompanying_course_index', {'accompanying_period_id': calendar.accompanyingPeriod.id}) }}" style="text-decoration: none;">
|
<a href="{{ chill_path_add_return_path('chill_person_accompanying_course_index', {'accompanying_period_id': calendar.accompanyingPeriod.id}) }}" style="text-decoration: none;">
|
||||||
<span class="badge bg-primary">
|
<span class="badge bg-primary">
|
||||||
@@ -19,6 +25,9 @@
|
|||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if calendar.status == 'canceled' %}
|
||||||
|
<del>
|
||||||
|
{% endif %}
|
||||||
{% if calendar.endDate.diff(calendar.startDate).days >= 1 %}
|
{% if calendar.endDate.diff(calendar.startDate).days >= 1 %}
|
||||||
{{ calendar.startDate|format_datetime('short', 'short') }}
|
{{ calendar.startDate|format_datetime('short', 'short') }}
|
||||||
- {{ calendar.endDate|format_datetime('short', 'short') }}
|
- {{ calendar.endDate|format_datetime('short', 'short') }}
|
||||||
@@ -26,44 +35,46 @@
|
|||||||
{{ calendar.startDate|format_datetime('short', 'short') }}
|
{{ calendar.startDate|format_datetime('short', 'short') }}
|
||||||
- {{ calendar.endDate|format_datetime('none', 'short') }}
|
- {{ calendar.endDate|format_datetime('none', 'short') }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
{% if calendar.status == 'canceled' %}
|
||||||
|
</del>
|
||||||
<div class="duration short-message">
|
|
||||||
<i class="fa fa-fw fa-hourglass-end"></i>
|
|
||||||
{{ calendar.duration|date('%H:%I') }}
|
|
||||||
{% if false == calendar.sendSMS or null == calendar.sendSMS %}
|
|
||||||
<!-- no sms will be send -->
|
|
||||||
{% else %}
|
|
||||||
{% if calendar.smsStatus == 'sms_sent' %}
|
|
||||||
<span title="{{ 'SMS already sent'|trans }}" class="badge bg-info">
|
|
||||||
<i class="fa fa-check "></i>
|
|
||||||
<i class="fa fa-envelope "></i>
|
|
||||||
</span>
|
|
||||||
{% else %}
|
|
||||||
<span title="{{ 'Will send SMS'|trans }}" class="badge bg-info">
|
|
||||||
<i class="fa fa-envelope "></i>
|
|
||||||
<i class="fa fa-hourglass-end "></i>
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
<div class="duration short-message">
|
||||||
</div>
|
<i class="fa fa-fw fa-hourglass-end"></i>
|
||||||
</div>
|
{{ calendar.duration|date('%H:%I') }}
|
||||||
|
{% if false == calendar.sendSMS or null == calendar.sendSMS %}
|
||||||
<div class="item-col">
|
<!-- no sms will be sent -->
|
||||||
<ul class="list-content">
|
{% else %}
|
||||||
{% if calendar.mainUser is not empty %}
|
{% if calendar.smsStatus == 'sms_sent' %}
|
||||||
<span class="badge-user">{{ calendar.mainUser|chill_entity_render_box({'at_date': calendar.startDate}) }}</span>
|
<span title="{{ 'SMS already sent'|trans }}" class="badge bg-info">
|
||||||
|
<i class="fa fa-check "></i>
|
||||||
|
<i class="fa fa-envelope "></i>
|
||||||
|
</span>
|
||||||
|
{% else %}
|
||||||
|
<span title="{{ 'Will send SMS'|trans }}" class="badge bg-info">
|
||||||
|
<i class="fa fa-envelope "></i>
|
||||||
|
<i class="fa fa-hourglass-end "></i>
|
||||||
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% if calendar.comment.comment is not empty
|
<div class="item-col">
|
||||||
|
<ul class="list-content">
|
||||||
|
{% if calendar.mainUser is not empty %}
|
||||||
|
<span class="badge-user">{{ calendar.mainUser|chill_entity_render_box({'at_date': calendar.startDate}) }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if calendar.comment.comment is not empty
|
||||||
or calendar.users|length > 0
|
or calendar.users|length > 0
|
||||||
or calendar.thirdParties|length > 0
|
or calendar.thirdParties|length > 0
|
||||||
or calendar.users|length > 0 %}
|
or calendar.users|length > 0 %}
|
||||||
@@ -76,131 +87,133 @@
|
|||||||
} %}
|
} %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if calendar.comment.comment is not empty %}
|
||||||
|
<div class="item-row details separator">
|
||||||
|
<div class="item-col comment">
|
||||||
|
{{ calendar.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if calendar.location is not empty %}
|
||||||
|
<div class="item-row separator">
|
||||||
|
<div>
|
||||||
|
{% if calendar.location.address is not same as(null) and calendar.location.name is not empty %}
|
||||||
|
<i class="fa fa-map-marker"></i>{% endif %}
|
||||||
|
{% if calendar.location.name is not empty %}{{ calendar.location.name }}{% endif %}
|
||||||
|
{% if calendar.location.address is not same as(null) %}{{ calendar.location.address|chill_entity_render_box({'multiline': false, 'with_picto': (calendar.location.name is empty)}) }}{% else %}
|
||||||
|
<i class="fa fa-map-marker"></i>{% endif %}
|
||||||
|
{% if calendar.location.phonenumber1 is not empty %}<i
|
||||||
|
class="fa fa-phone"></i> {{ calendar.location.phonenumber1|chill_format_phonenumber }}{% endif %}
|
||||||
|
{% if calendar.location.phonenumber2 is not empty %}<i
|
||||||
|
class="fa fa-phone"></i> {{ calendar.location.phonenumber2|chill_format_phonenumber }}{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if calendar.documents is not empty %}
|
||||||
|
<div class="item-row separator column">
|
||||||
|
<div>
|
||||||
|
{{ include('@ChillCalendar/Calendar/_documents.twig.html') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if calendar.activity is not null %}
|
||||||
|
<div class="item-row separator">
|
||||||
|
<div class="item-col">
|
||||||
|
<div class="wrap-list">
|
||||||
|
<div class="wl-row">
|
||||||
|
<div class="wl-col title"><h3>{{ 'Activity'|trans }}</h3></div>
|
||||||
|
<div class="wl-col list activity-linked">
|
||||||
|
<h2 class="badge-title">
|
||||||
|
<span class="title_label"></span>
|
||||||
|
<span class="title_action">
|
||||||
|
{{ calendar.activity.type.name | localize_translatable_string }}
|
||||||
|
|
||||||
|
{% if calendar.activity.emergency %}
|
||||||
|
<span class="badge bg-danger rounded-pill fs-6 float-end">{{ 'Emergency'|trans|upper }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li class="cancel">
|
||||||
|
<span class="createdBy">
|
||||||
|
{{ 'Created by'|trans }}
|
||||||
|
<b>{{ calendar.activity.createdBy|chill_entity_render_string({'at_date': calendar.activity.createdAt}) }}</b>, {{ 'on'|trans }} {{ calendar.activity.createdAt|format_datetime('short', 'short') }}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
{% if is_granted('CHILL_ACTIVITY_SEE', calendar.activity) %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_activity_activity_show', {'id': calendar.activity.id}) }}" class="btn btn-sm btn-show" ></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
{% if calendar.comment.comment is not empty %}
|
|
||||||
<div class="item-row details separator">
|
|
||||||
<div class="item-col comment">
|
|
||||||
{{ calendar.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if calendar.location is not empty %}
|
|
||||||
<div class="item-row separator">
|
|
||||||
<div>
|
|
||||||
{% if calendar.location.address is not same as(null) and calendar.location.name is not empty %}
|
|
||||||
<i class="fa fa-map-marker"></i>{% endif %}
|
|
||||||
{% if calendar.location.name is not empty %}{{ calendar.location.name }}{% endif %}
|
|
||||||
{% if calendar.location.address is not same as(null) %}{{ calendar.location.address|chill_entity_render_box({'multiline': false, 'with_picto': (calendar.location.name is empty)}) }}{% else %}
|
|
||||||
<i class="fa fa-map-marker"></i>{% endif %}
|
|
||||||
{% if calendar.location.phonenumber1 is not empty %}<i
|
|
||||||
class="fa fa-phone"></i> {{ calendar.location.phonenumber1|chill_format_phonenumber }}{% endif %}
|
|
||||||
{% if calendar.location.phonenumber2 is not empty %}<i
|
|
||||||
class="fa fa-phone"></i> {{ calendar.location.phonenumber2|chill_format_phonenumber }}{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="item-row separator column">
|
|
||||||
<div>
|
|
||||||
|
|
||||||
{{ include('@ChillCalendar/Calendar/_documents.twig.html') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if calendar.activity is not null %}
|
<div class="item-row separator">
|
||||||
<div class="item-row separator">
|
<ul class="record_actions">
|
||||||
<div class="item-col">
|
{% if is_granted('CHILL_CALENDAR_DOC_EDIT', calendar) and calendar.status is not constant('STATUS_CANCELED', calendar) %}
|
||||||
<div class="wrap-list">
|
{% if templates|length == 0 %}
|
||||||
<div class="wl-row">
|
<li>
|
||||||
<div class="wl-col title"><h3>{{ 'Activity'|trans }}</h3></div>
|
<a class="btn btn-create"
|
||||||
<div class="wl-col list activity-linked">
|
href="{{ chill_path_add_return_path('chill_calendar_calendardoc_new', {'id': calendar.id }) }}">
|
||||||
<h2 class="badge-title">
|
{{ 'chill_calendar.Add a document'|trans }}
|
||||||
<span class="title_label"></span>
|
</a>
|
||||||
<span class="title_action">
|
</li>
|
||||||
{{ calendar.activity.type.name | localize_translatable_string }}
|
{% else %}
|
||||||
|
<li>
|
||||||
{% if calendar.activity.emergency %}
|
<div class="dropdown">
|
||||||
<span class="badge bg-danger rounded-pill fs-6 float-end">{{ 'Emergency'|trans|upper }}</span>
|
<button class="btn btn-create dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
{% endif %}
|
{{ 'chill_calendar.Add a document'|trans }}
|
||||||
</span>
|
</button>
|
||||||
</h2>
|
<ul class="dropdown-menu">
|
||||||
|
<li>
|
||||||
<ul class="record_actions">
|
<a class="dropdown-item"
|
||||||
<li class="cancel">
|
href="{{ chill_path_add_return_path('chill_calendar_calendardoc_new', {'id': calendar.id }) }}">
|
||||||
<span class="createdBy">
|
{{ 'chill_calendar.Upload a document'|trans }}
|
||||||
{{ 'Created by'|trans }}
|
</a>
|
||||||
<b>{{ calendar.activity.createdBy|chill_entity_render_string({'at_date': calendar.activity.createdAt}) }}</b>, {{ 'on'|trans }} {{ calendar.activity.createdAt|format_datetime('short', 'short') }}
|
</li>
|
||||||
</span>
|
{% for template in templates %}
|
||||||
</li>
|
<li>
|
||||||
{% if is_granted('CHILL_ACTIVITY_SEE', calendar.activity) %}
|
<a class="dropdown-item"
|
||||||
<li>
|
href="{{ chill_path_add_return_path('chill_docgenerator_generate_from_template', {'template': template.id, 'entityClassName': 'Chill\\CalendarBundle\\Entity\\Calendar', 'entityId': calendar.id}) }}"
|
||||||
<a href="{{ chill_path_add_return_path('chill_activity_activity_show', {'id': calendar.activity.id}) }}" class="btn btn-sm btn-show" ></a>
|
>
|
||||||
</li>
|
{{ template.name|localize_translatable_string }}
|
||||||
{% endif %}
|
</a>
|
||||||
</ul>
|
</li>
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</ul>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</li>
|
||||||
</div>
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if calendar.activity is null and (
|
||||||
|
(calendar.context == 'accompanying_period' and is_granted('CHILL_ACTIVITY_CREATE', calendar.accompanyingPeriod))
|
||||||
|
or
|
||||||
|
(calendar.context == 'person' and is_granted('CHILL_ACTIVITY_CREATE', calendar.person))
|
||||||
|
)
|
||||||
|
and calendar.status is not constant('STATUS_CANCELED', calendar)
|
||||||
|
%}
|
||||||
|
<li>
|
||||||
|
<a class="btn btn-create"
|
||||||
|
href="{{ chill_path_add_return_path('chill_calendar_calendar_to_activity', { 'id': calendar.id }) }}">
|
||||||
|
{{ 'Transform to activity'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="item-row separator">
|
{% if calendar.isInvited(app.user) and not calendar.isCanceled %}
|
||||||
<ul class="record_actions">
|
|
||||||
{% if is_granted('CHILL_CALENDAR_DOC_EDIT', calendar) %}
|
|
||||||
{% if templates|length == 0 %}
|
|
||||||
<li>
|
|
||||||
<a class="btn btn-create"
|
|
||||||
href="{{ chill_path_add_return_path('chill_calendar_calendardoc_new', {'id': calendar.id }) }}">
|
|
||||||
{{ 'chill_calendar.Add a document'|trans }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% else %}
|
|
||||||
<li>
|
|
||||||
<div class="dropdown">
|
|
||||||
<button class="btn btn-create dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
||||||
{{ 'chill_calendar.Add a document'|trans }}
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{{ chill_path_add_return_path('chill_calendar_calendardoc_new', {'id': calendar.id }) }}">
|
|
||||||
{{ 'chill_calendar.Upload a document'|trans }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% for template in templates %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{{ chill_path_add_return_path('chill_docgenerator_generate_from_template', {'template': template.id, 'entityClassName': 'Chill\\CalendarBundle\\Entity\\Calendar', 'entityId': calendar.id}) }}"
|
|
||||||
>
|
|
||||||
{{ template.name|localize_translatable_string }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% if calendar.activity is null and (
|
|
||||||
(calendar.context == 'accompanying_period' and is_granted('CHILL_ACTIVITY_CREATE', calendar.accompanyingPeriod))
|
|
||||||
or
|
|
||||||
(calendar.context == 'person' and is_granted('CHILL_ACTIVITY_CREATE', calendar.person))
|
|
||||||
)
|
|
||||||
%}
|
|
||||||
<li>
|
|
||||||
<a class="btn btn-create"
|
|
||||||
href="{{ chill_path_add_return_path('chill_calendar_calendar_to_activity', { 'id': calendar.id }) }}">
|
|
||||||
{{ 'Transform to activity'|trans }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if (calendar.isInvited(app.user)) %}
|
|
||||||
{% set invite = calendar.inviteForUser(app.user) %}
|
{% set invite = calendar.inviteForUser(app.user) %}
|
||||||
<li>
|
<li>
|
||||||
<div invite-answer data-status="{{ invite.status|e('html_attr') }}"
|
<div invite-answer data-status="{{ invite.status|e('html_attr') }}"
|
||||||
@@ -213,12 +226,18 @@
|
|||||||
class="btn btn-show "></a>
|
class="btn btn-show "></a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if is_granted('CHILL_CALENDAR_CALENDAR_EDIT', calendar) %}
|
|
||||||
|
{% if is_granted('CHILL_CALENDAR_CALENDAR_EDIT', calendar) and calendar.status is not constant('STATUS_CANCELED', calendar) %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_edit', { 'id': calendar.id }) }}"
|
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_edit', { 'id': calendar.id }) }}"
|
||||||
class="btn btn-update "></a>
|
class="btn btn-update "></a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_cancel', { 'id': calendar.id } ) }}"
|
||||||
|
class="btn btn-action"><i class="bi bi-x-circle"></i> {{ 'Cancel'|trans }}</a>
|
||||||
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if is_granted('CHILL_CALENDAR_CALENDAR_DELETE', calendar) %}
|
{% if is_granted('CHILL_CALENDAR_CALENDAR_DELETE', calendar) %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_delete', { 'id': calendar.id } ) }}"
|
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_delete', { 'id': calendar.id } ) }}"
|
||||||
@@ -227,14 +246,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% if calendarItems|length < paginator.getTotalItems %}
|
|
||||||
{{ chill_pagination(paginator) }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user