mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-11-07 20:58:24 +00:00
Compare commits
264 Commits
v4.6.1
...
ticket-app
| Author | SHA1 | Date | |
|---|---|---|---|
| 65bbdc283d | |||
|
|
f0b3e63d66 | ||
| 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 | |||
| a22cbe0239 | |||
| 98902bdeb8 | |||
| 4765d4fe28 | |||
|
|
30bcb85549 | ||
|
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
|
||||||
@@ -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,11 +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 a specific test file
|
# Run a specific test file
|
||||||
vendor/bin/phpunit path/to/TestFile.php
|
vendor/bin/phpunit path/to/TestFile.php
|
||||||
|
|||||||
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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -780,7 +780,7 @@ 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
|
||||||
@@ -960,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],
|
||||||
];
|
];
|
||||||
|
|||||||
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',
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = 'chill_calendar_calendar_list' %}
|
||||||
|
|
||||||
|
{% block title 'chill_calendar.cancel_calendar_item'|trans %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{{ form_start(form) }}
|
||||||
|
|
||||||
|
{{ form_row(form.cancelReason) }}
|
||||||
|
|
||||||
|
<ul class="record_actions sticky-form-buttons">
|
||||||
|
<li class="cancel">
|
||||||
|
<a
|
||||||
|
class="btn btn-cancel"
|
||||||
|
href="{{ chill_return_path_or('chill_calendar_calendar_list', { 'id': accompanyingCourse.id } )}}"
|
||||||
|
>
|
||||||
|
{{ 'Cancel'|trans|chill_return_path_label }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{ form_widget(form.submit, { 'attr' : { 'class': 'btn btn-save' }, 'label': 'Save' } ) }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{ form_end(form) }}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{% extends "@ChillPerson/Person/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = 'chill_calendar_calendar_list' %}
|
||||||
|
|
||||||
|
{% block title 'chill_calendar.cancel_calendar_item'|trans %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{{ form_start(form) }}
|
||||||
|
|
||||||
|
{{ form_row(form.cancelReason) }}
|
||||||
|
|
||||||
|
<ul class="record_actions sticky-form-buttons">
|
||||||
|
<li class="cancel">
|
||||||
|
<a
|
||||||
|
class="btn btn-cancel"
|
||||||
|
href="{{ chill_return_path_or('chill_calendar_calendar_list', { 'id': person.id } )}}"
|
||||||
|
>
|
||||||
|
{{ 'Cancel'|trans|chill_return_path_label }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{ form_widget(form.submit, { 'attr' : { 'class': 'btn btn-save' }, 'label': 'Save' } ) }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{ form_end(form) }}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -34,7 +34,18 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ include('@ChillCalendar/Calendar/_list.html.twig', {context: 'accompanying_course'}) }}
|
{% if calendarItems|length > 0 %}
|
||||||
|
<div class="flex-table list-records context-accompanyingCourse">
|
||||||
|
{% for calendar in calendarItems %}
|
||||||
|
{{ include('@ChillCalendar/Calendar/_list.html.twig', {context: 'accompanying_course'}) }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if calendarItems|length < paginator.getTotalItems %}
|
||||||
|
{{ chill_pagination(paginator) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<ul class="record_actions sticky-form-buttons">
|
<ul class="record_actions sticky-form-buttons">
|
||||||
|
|||||||
@@ -33,7 +33,17 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ include ('@ChillCalendar/Calendar/_list.html.twig', {context: 'person'}) }}
|
{% if calendarItems|length > 0 %}
|
||||||
|
<div class="flex-table list-records context-person">
|
||||||
|
{% for calendar in calendarItems %}
|
||||||
|
{{ include ('@ChillCalendar/Calendar/_list.html.twig', {context: 'person'}) }}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if calendarItems|length < paginator.getTotalItems %}
|
||||||
|
{{ chill_pagination(paginator) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<ul class="record_actions sticky-form-buttons">
|
<ul class="record_actions sticky-form-buttons">
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
{% block table_entities_thead_tr %}
|
{% block table_entities_thead_tr %}
|
||||||
<th>{{ 'Id'|trans }}</th>
|
<th>{{ 'Id'|trans }}</th>
|
||||||
<th>{{ 'Name'|trans }}</th>
|
<th>{{ 'Name'|trans }}</th>
|
||||||
<th>{{ 'canceledBy'|trans }}</th>
|
<th>{{ 'Canceled by'|trans }}</th>
|
||||||
<th>{{ 'active'|trans }}</th>
|
<th>{{ 'active'|trans }}</th>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user