mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-26 16:45:01 +00:00
Compare commits
16 Commits
ticket/WP1
...
v4.4.2
Author | SHA1 | Date | |
---|---|---|---|
ab98f3a102
|
|||
7516e68d77 | |||
7b60b7a8af | |||
d984dec7db
|
|||
46a4dedab8 | |||
db98519e65 | |||
c39637180a
|
|||
15f9409bc8 | |||
5b90d23367 | |||
c48625d1cd | |||
1195b54a68 | |||
2a280b814f | |||
230c758255 | |||
eafda987ae | |||
7db8a371fc | |||
0d0649dd31 |
@@ -1,6 +0,0 @@
|
|||||||
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: ""
|
|
@@ -1,6 +0,0 @@
|
|||||||
kind: Feature
|
|
||||||
body: |
|
|
||||||
Upgrade CKEditor and refactor configuration with use of typescript
|
|
||||||
time: 2024-05-31T19:02:42.776662753+02:00
|
|
||||||
custom:
|
|
||||||
Issue: ""
|
|
@@ -1,6 +0,0 @@
|
|||||||
kind: Feature
|
|
||||||
body: Add a command to generate a list of permissions
|
|
||||||
time: 2025-09-04T18:10:32.334524026+02:00
|
|
||||||
custom:
|
|
||||||
Issue: ""
|
|
||||||
SchemaChange: No schema change
|
|
10
.changes/v4.3.0.md
Normal file
10
.changes/v4.3.0.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
## v4.3.0 - 2025-09-08
|
||||||
|
### Feature
|
||||||
|
* ([#409](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/409)) Add 45 and 60 min calendar ranges
|
||||||
|
* Add a command to generate a list of permissions
|
||||||
|
* ([#412](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/412)) Add an absence end date
|
||||||
|
|
||||||
|
**Schema Change**: Add columns or tables
|
||||||
|
### Fixed
|
||||||
|
* fix date formatting in calendar range display
|
||||||
|
* Change route URL to avoid clash with person duplicate controller method
|
8
.changes/v4.4.0.md
Normal file
8
.changes/v4.4.0.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
## v4.4.0 - 2025-09-11
|
||||||
|
### Feature
|
||||||
|
* ([#359](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/359)) Allow the merge of two accompanying period works
|
||||||
|
* ([#369](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/369)) Duplication of a document to another accompanying period work evaluation
|
||||||
|
* ([#359](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/359)) Fusion of two accompanying period works
|
||||||
|
### Fixed
|
||||||
|
* Fix display of 'duplicate' and 'merge' buttons in CRUD templates
|
||||||
|
* Fix saving notification preferences in user's profile
|
3
.changes/v4.4.1.md
Normal file
3
.changes/v4.4.1.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
## v4.4.1 - 2025-09-11
|
||||||
|
### Fixed
|
||||||
|
* fix translations in duplicate evaluation document modal and realign close modal button
|
3
.changes/v4.4.2.md
Normal file
3
.changes/v4.4.2.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
## v4.4.2 - 2025-09-12
|
||||||
|
### Fixed
|
||||||
|
* Fix document generation and workflow generation do not work on accompanying period work documents
|
@@ -23,7 +23,7 @@ max_line_length = 0
|
|||||||
indent_size = 2
|
indent_size = 2
|
||||||
indent_style = space
|
indent_style = space
|
||||||
|
|
||||||
[*.rst]
|
[.rst]
|
||||||
indent_size = 3
|
ident_size = 3
|
||||||
indent_style = space
|
ident_style = space
|
||||||
|
|
||||||
|
@@ -234,9 +234,15 @@ 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: so, do not change the directory to any bundle directory before running tests).
|
The tests are run from the project's root (not from the bundle's root).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Run all tests
|
||||||
|
vendor/bin/phpunit
|
||||||
|
|
||||||
|
# Run tests for a specific bundle
|
||||||
|
vendor/bin/phpunit --testsuite NameBundle
|
||||||
|
|
||||||
# Run a specific test file
|
# Run a specific test file
|
||||||
vendor/bin/phpunit path/to/TestFile.php
|
vendor/bin/phpunit path/to/TestFile.php
|
||||||
|
|
||||||
|
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"tabWidth": 2,
|
|
||||||
"useTabs": false
|
|
||||||
}
|
|
30
.vscode/launch.json
vendored
30
.vscode/launch.json
vendored
@@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
// 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
23
.vscode/tasks.json
vendored
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
28
CHANGELOG.md
28
CHANGELOG.md
@@ -6,6 +6,34 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
|
|||||||
and is generated by [Changie](https://github.com/miniscruff/changie).
|
and is generated by [Changie](https://github.com/miniscruff/changie).
|
||||||
|
|
||||||
|
|
||||||
|
## v4.4.2 - 2025-09-12
|
||||||
|
### Fixed
|
||||||
|
* Fix document generation and workflow generation do not work on accompanying period work documents
|
||||||
|
|
||||||
|
## v4.4.1 - 2025-09-11
|
||||||
|
### Fixed
|
||||||
|
* fix translations in duplicate evaluation document modal and realign close modal button
|
||||||
|
|
||||||
|
## v4.4.0 - 2025-09-11
|
||||||
|
### Feature
|
||||||
|
* ([#359](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/359)) Allow the merge of two accompanying period works
|
||||||
|
* ([#369](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/369)) Duplication of a document to another accompanying period work evaluation
|
||||||
|
* ([#359](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/359)) Fusion of two accompanying period works
|
||||||
|
### Fixed
|
||||||
|
* Fix display of 'duplicate' and 'merge' buttons in CRUD templates
|
||||||
|
* Fix saving notification preferences in user's profile
|
||||||
|
|
||||||
|
## v4.3.0 - 2025-09-08
|
||||||
|
### Feature
|
||||||
|
* ([#409](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/409)) Add 45 and 60 min calendar ranges
|
||||||
|
* Add a command to generate a list of permissions
|
||||||
|
* ([#412](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/412)) Add an absence end date
|
||||||
|
|
||||||
|
**Schema Change**: Add columns or tables
|
||||||
|
### Fixed
|
||||||
|
* fix date formatting in calendar range display
|
||||||
|
* Change route URL to avoid clash with person duplicate controller method
|
||||||
|
|
||||||
## v4.2.1 - 2025-09-03
|
## v4.2.1 - 2025-09-03
|
||||||
### Fixed
|
### Fixed
|
||||||
* Fix exports to work with DirectExportInterface
|
* Fix exports to work with DirectExportInterface
|
||||||
|
@@ -54,7 +54,7 @@ Arborescence:
|
|||||||
- person
|
- person
|
||||||
- personvendee
|
- personvendee
|
||||||
- household_edit_metadata
|
- household_edit_metadata
|
||||||
- index.ts
|
- index.js
|
||||||
```
|
```
|
||||||
|
|
||||||
## Organisation des feuilles de styles
|
## Organisation des feuilles de styles
|
||||||
|
@@ -133,7 +133,6 @@
|
|||||||
"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"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -35,7 +35,6 @@ 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],
|
||||||
];
|
];
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
chill_doc_store:
|
chill_doc_store:
|
||||||
use_driver: local_storage
|
use_driver: openstack
|
||||||
local_storage:
|
local_storage:
|
||||||
storage_path: '%kernel.project_dir%/var/storage'
|
storage_path: '%kernel.project_dir%/var/storage'
|
||||||
openstack:
|
openstack:
|
||||||
|
@@ -1,5 +0,0 @@
|
|||||||
chill_ticket:
|
|
||||||
ticket:
|
|
||||||
person_per_ticket: one # One of "one"; "many"
|
|
||||||
response_time_exceeded_delay: PT12H
|
|
||||||
|
|
@@ -14,7 +14,6 @@ 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
|
||||||
|
|
||||||
|
@@ -1,2 +0,0 @@
|
|||||||
chill_ticket_bundle:
|
|
||||||
resource: '@ChillTicketBundle/config/routes.yaml'
|
|
@@ -11,94 +11,24 @@
|
|||||||
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
|
||||||
|
|
||||||
Create a new directory with Bundle class
|
TODO
|
||||||
----------------------------------------
|
|
||||||
|
|
||||||
.. 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",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Register the bundle
|
.. rubric:: Footnotes
|
||||||
-------------------
|
|
||||||
|
|
||||||
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.
|
||||||
|
@@ -79,12 +79,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 src/Bundle/ChillTicketBundle/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> 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": "eslint-baseline --fix \"src/**/*.{js,ts,vue}\""
|
"eslint": "npx eslint-baseline --fix \"src/**/*.{js,ts,vue}\""
|
||||||
},
|
},
|
||||||
"private": true
|
"private": true
|
||||||
}
|
}
|
||||||
|
@@ -58,10 +58,6 @@
|
|||||||
<!-- 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>
|
||||||
|
@@ -10,7 +10,10 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="getContext === 'accompanyingCourse' && suggestedEntities.length > 0"
|
v-if="
|
||||||
|
getContext === 'accompanyingCourse' &&
|
||||||
|
suggestedEntities.length > 0
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<ul class="list-suggest add-items inline">
|
<ul class="list-suggest add-items inline">
|
||||||
<li
|
<li
|
||||||
|
@@ -39,11 +39,17 @@
|
|||||||
<option selected disabled value="">
|
<option selected disabled value="">
|
||||||
{{ trans(ACTIVITY_CHOOSE_LOCATION_TYPE) }}
|
{{ trans(ACTIVITY_CHOOSE_LOCATION_TYPE) }}
|
||||||
</option>
|
</option>
|
||||||
<option v-for="t in locationTypes" :value="t" :key="t.id">
|
<option
|
||||||
|
v-for="t in locationTypes"
|
||||||
|
:value="t"
|
||||||
|
:key="t.id"
|
||||||
|
>
|
||||||
{{ localizeString(t.title) }}
|
{{ localizeString(t.title) }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<label>{{ trans(ACTIVITY_LOCATION_FIELDS_TYPE) }}</label>
|
<label>{{
|
||||||
|
trans(ACTIVITY_LOCATION_FIELDS_TYPE)
|
||||||
|
}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-floating mb-3">
|
<div class="form-floating mb-3">
|
||||||
@@ -102,7 +108,10 @@
|
|||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<button class="btn btn-save" @click.prevent="saveNewLocation">
|
<button
|
||||||
|
class="btn btn-save"
|
||||||
|
@click.prevent="saveNewLocation"
|
||||||
|
>
|
||||||
{{ trans(SAVE) }}
|
{{ trans(SAVE) }}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
@@ -235,7 +244,8 @@ export default {
|
|||||||
},
|
},
|
||||||
hasPhonenumber1() {
|
hasPhonenumber1() {
|
||||||
return (
|
return (
|
||||||
this.selected.phonenumber1 !== null && this.selected.phonenumber1 !== ""
|
this.selected.phonenumber1 !== null &&
|
||||||
|
this.selected.phonenumber1 !== ""
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
showAddAddress() {
|
showAddAddress() {
|
||||||
|
@@ -49,7 +49,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-8">
|
<div class="col-8">
|
||||||
<div v-if="actionIsLoading === true">
|
<div v-if="actionIsLoading === true">
|
||||||
<i class="chill-green fa fa-circle-o-notch fa-spin fa-lg"></i>
|
<i
|
||||||
|
class="chill-green fa fa-circle-o-notch fa-spin fa-lg"
|
||||||
|
></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
@@ -62,7 +64,8 @@
|
|||||||
<template
|
<template
|
||||||
v-else-if="
|
v-else-if="
|
||||||
socialActionsList.length > 0 &&
|
socialActionsList.length > 0 &&
|
||||||
(socialIssuesSelected.length || socialActionsSelected.length)
|
(socialIssuesSelected.length ||
|
||||||
|
socialActionsSelected.length)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -85,7 +88,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
v-else-if="actionAreLoaded && socialActionsList.length === 0"
|
v-else-if="
|
||||||
|
actionAreLoaded && socialActionsList.length === 0
|
||||||
|
"
|
||||||
class="inline-choice chill-no-data-statement mt-3"
|
class="inline-choice chill-no-data-statement mt-3"
|
||||||
>
|
>
|
||||||
{{ trans(ACTIVITY_SOCIAL_ACTION_LIST_EMPTY) }}
|
{{ trans(ACTIVITY_SOCIAL_ACTION_LIST_EMPTY) }}
|
||||||
@@ -164,7 +169,8 @@ export default {
|
|||||||
/* Add in list the issues already associated (if not yet listed) */
|
/* Add in list the issues already associated (if not yet listed) */
|
||||||
this.socialIssuesSelected.forEach((issue) => {
|
this.socialIssuesSelected.forEach((issue) => {
|
||||||
if (
|
if (
|
||||||
this.socialIssuesList.filter((i) => i.id === issue.id).length !== 1
|
this.socialIssuesList.filter((i) => i.id === issue.id)
|
||||||
|
.length !== 1
|
||||||
) {
|
) {
|
||||||
this.$store.commit("addIssueInList", issue);
|
this.$store.commit("addIssueInList", issue);
|
||||||
}
|
}
|
||||||
|
@@ -10,7 +10,9 @@
|
|||||||
: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">{{ issue.text }}</span>
|
<span class="badge bg-chill-l-gray text-dark">{{
|
||||||
|
issue.text
|
||||||
|
}}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
@@ -55,5 +55,6 @@
|
|||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
{% block content_view_actions_duplicate_link %}{% endblock %}
|
||||||
{% endembed %}
|
{% endembed %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -68,7 +68,9 @@ export type EventInputCalendarRange = EventInput & {
|
|||||||
export function isEventInputCalendarRange(
|
export function isEventInputCalendarRange(
|
||||||
toBeDetermined: EventInputCalendarRange | EventInput,
|
toBeDetermined: EventInputCalendarRange | EventInput,
|
||||||
): toBeDetermined is EventInputCalendarRange {
|
): toBeDetermined is EventInputCalendarRange {
|
||||||
return typeof toBeDetermined.is === "string" && toBeDetermined.is === "range";
|
return (
|
||||||
|
typeof toBeDetermined.is === "string" && toBeDetermined.is === "range"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export {};
|
export {};
|
||||||
|
@@ -61,14 +61,24 @@
|
|||||||
<label class="input-group-text" for="slotDuration"
|
<label class="input-group-text" for="slotDuration"
|
||||||
>Durée des créneaux</label
|
>Durée des créneaux</label
|
||||||
>
|
>
|
||||||
<select v-model="slotDuration" id="slotDuration" class="form-select">
|
<select
|
||||||
|
v-model="slotDuration"
|
||||||
|
id="slotDuration"
|
||||||
|
class="form-select"
|
||||||
|
>
|
||||||
<option value="00:05:00">5 minutes</option>
|
<option value="00:05:00">5 minutes</option>
|
||||||
<option value="00:10:00">10 minutes</option>
|
<option value="00:10:00">10 minutes</option>
|
||||||
<option value="00:15:00">15 minutes</option>
|
<option value="00:15:00">15 minutes</option>
|
||||||
<option value="00:30:00">30 minutes</option>
|
<option value="00:30:00">30 minutes</option>
|
||||||
|
<option value="00:45:00">45 minutes</option>
|
||||||
|
<option value="00:60:00">60 minutes</option>
|
||||||
</select>
|
</select>
|
||||||
<label class="input-group-text" for="slotMinTime">De</label>
|
<label class="input-group-text" for="slotMinTime">De</label>
|
||||||
<select v-model="slotMinTime" id="slotMinTime" class="form-select">
|
<select
|
||||||
|
v-model="slotMinTime"
|
||||||
|
id="slotMinTime"
|
||||||
|
class="form-select"
|
||||||
|
>
|
||||||
<option value="00:00:00">0h</option>
|
<option value="00:00:00">0h</option>
|
||||||
<option value="01:00:00">1h</option>
|
<option value="01:00:00">1h</option>
|
||||||
<option value="02:00:00">2h</option>
|
<option value="02:00:00">2h</option>
|
||||||
@@ -84,7 +94,11 @@
|
|||||||
<option value="12:00:00">12h</option>
|
<option value="12:00:00">12h</option>
|
||||||
</select>
|
</select>
|
||||||
<label class="input-group-text" for="slotMaxTime">À</label>
|
<label class="input-group-text" for="slotMaxTime">À</label>
|
||||||
<select v-model="slotMaxTime" id="slotMaxTime" class="form-select">
|
<select
|
||||||
|
v-model="slotMaxTime"
|
||||||
|
id="slotMaxTime"
|
||||||
|
class="form-select"
|
||||||
|
>
|
||||||
<option value="12:00:00">12h</option>
|
<option value="12:00:00">12h</option>
|
||||||
<option value="13:00:00">13h</option>
|
<option value="13:00:00">13h</option>
|
||||||
<option value="14:00:00">14h</option>
|
<option value="14:00:00">14h</option>
|
||||||
@@ -112,7 +126,9 @@
|
|||||||
v-model="hideWeekends"
|
v-model="hideWeekends"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<label for="showHideWE" class="form-check-label input-group-text"
|
<label
|
||||||
|
for="showHideWE"
|
||||||
|
class="form-check-label input-group-text"
|
||||||
>Week-ends</label
|
>Week-ends</label
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
@@ -128,7 +144,9 @@
|
|||||||
<b v-else-if="arg.event.extendedProps.is === 'range'"
|
<b v-else-if="arg.event.extendedProps.is === 'range'"
|
||||||
>{{ arg.timeText }}
|
>{{ arg.timeText }}
|
||||||
{{ arg.event.extendedProps.locationName }}
|
{{ arg.event.extendedProps.locationName }}
|
||||||
<small>{{ arg.event.extendedProps.userLabel }}</small></b
|
<small>{{
|
||||||
|
arg.event.extendedProps.userLabel
|
||||||
|
}}</small></b
|
||||||
>
|
>
|
||||||
<b v-else-if="arg.event.extendedProps.is === 'current'"
|
<b v-else-if="arg.event.extendedProps.is === 'current'"
|
||||||
>{{ arg.timeText }} {{ $t("current_selected") }}
|
>{{ arg.timeText }} {{ $t("current_selected") }}
|
||||||
@@ -136,7 +154,9 @@
|
|||||||
<b v-else-if="arg.event.extendedProps.is === 'local'">{{
|
<b v-else-if="arg.event.extendedProps.is === 'local'">{{
|
||||||
arg.event.title
|
arg.event.title
|
||||||
}}</b>
|
}}</b>
|
||||||
<b v-else>{{ arg.timeText }} {{ $t("current_selected") }} </b>
|
<b v-else
|
||||||
|
>{{ arg.timeText }} {{ $t("current_selected") }}
|
||||||
|
</b>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</FullCalendar>
|
</FullCalendar>
|
||||||
@@ -250,7 +270,9 @@ export default {
|
|||||||
this.$store.state.activity.endDate !== null)
|
this.$store.state.activity.endDate !== null)
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
!window.confirm(this.$t("change_main_user_will_reset_event_data"))
|
!window.confirm(
|
||||||
|
this.$t("change_main_user_will_reset_event_data"),
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -258,9 +280,13 @@ export default {
|
|||||||
|
|
||||||
// add the previous user, if any, in the previous user list (in use for suggestion)
|
// add the previous user, if any, in the previous user list (in use for suggestion)
|
||||||
if (null !== this.$store.getters.getMainUser) {
|
if (null !== this.$store.getters.getMainUser) {
|
||||||
const suggestedUids = new Set(this.$data.previousUser.map((u) => u.id));
|
const suggestedUids = new Set(
|
||||||
|
this.$data.previousUser.map((u) => u.id),
|
||||||
|
);
|
||||||
if (!suggestedUids.has(this.$store.getters.getMainUser.id)) {
|
if (!suggestedUids.has(this.$store.getters.getMainUser.id)) {
|
||||||
this.$data.previousUser.push(this.$store.getters.getMainUser);
|
this.$data.previousUser.push(
|
||||||
|
this.$store.getters.getMainUser,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,7 +316,8 @@ export default {
|
|||||||
// show an alert if changing mainUser
|
// show an alert if changing mainUser
|
||||||
if (
|
if (
|
||||||
(this.$store.getters.getMainUser !== null &&
|
(this.$store.getters.getMainUser !== null &&
|
||||||
this.$store.state.me.id !== this.$store.getters.getMainUser.id) ||
|
this.$store.state.me.id !==
|
||||||
|
this.$store.getters.getMainUser.id) ||
|
||||||
this.$store.getters.getMainUser === null
|
this.$store.getters.getMainUser === null
|
||||||
) {
|
) {
|
||||||
if (!window.confirm(this.$t("will_change_main_user_for_me"))) {
|
if (!window.confirm(this.$t("will_change_main_user_for_me"))) {
|
||||||
@@ -334,7 +361,9 @@ export default {
|
|||||||
this.$store.getters.getMainUser.id
|
this.$store.getters.getMainUser.id
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
!window.confirm(this.$t("this_calendar_range_will_change_main_user"))
|
!window.confirm(
|
||||||
|
this.$t("this_calendar_range_will_change_main_user"),
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -4,9 +4,18 @@
|
|||||||
{{ 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 v-else-if="invite.status === 'declined'" class="fa fa-times" />
|
<i
|
||||||
<i v-else-if="invite.status === 'pending'" class="fa fa-question-o" />
|
v-else-if="invite.status === 'declined'"
|
||||||
<i v-else-if="invite.status === 'tentative'" class="fa fa-question" />
|
class="fa fa-times"
|
||||||
|
/>
|
||||||
|
<i
|
||||||
|
v-else-if="invite.status === 'pending'"
|
||||||
|
class="fa fa-question-o"
|
||||||
|
/>
|
||||||
|
<i
|
||||||
|
v-else-if="invite.status === 'tentative'"
|
||||||
|
class="fa fa-question"
|
||||||
|
/>
|
||||||
<span v-else="">{{ invite.status }}</span>
|
<span v-else="">{{ invite.status }}</span>
|
||||||
</template>
|
</template>
|
||||||
</span>
|
</span>
|
||||||
@@ -60,7 +69,8 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
style() {
|
style() {
|
||||||
return {
|
return {
|
||||||
backgroundColor: this.$store.getters.getUserData(this.user).mainColor,
|
backgroundColor: this.$store.getters.getUserData(this.user)
|
||||||
|
.mainColor,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
rangeShow: {
|
rangeShow: {
|
||||||
@@ -71,7 +81,9 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
get() {
|
get() {
|
||||||
return this.$store.getters.isRangeShownOnCalendarForUser(this.user);
|
return this.$store.getters.isRangeShownOnCalendarForUser(
|
||||||
|
this.user,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
remoteShow: {
|
remoteShow: {
|
||||||
@@ -82,7 +94,9 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
get() {
|
get() {
|
||||||
return this.$store.getters.isRemoteShownOnCalendarForUser(this.user);
|
return this.$store.getters.isRemoteShownOnCalendarForUser(
|
||||||
|
this.user,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@@ -22,25 +22,33 @@
|
|||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
|
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
|
||||||
<li v-if="status !== Statuses.ACCEPTED">
|
<li v-if="status !== Statuses.ACCEPTED">
|
||||||
<a class="dropdown-item" @click="changeStatus(Statuses.ACCEPTED)"
|
<a
|
||||||
><i class="fa fa-check" aria-hidden="true"></i> {{ $t("Accept") }}</a
|
class="dropdown-item"
|
||||||
|
@click="changeStatus(Statuses.ACCEPTED)"
|
||||||
|
><i class="fa fa-check" aria-hidden="true"></i>
|
||||||
|
{{ $t("Accept") }}</a
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="status !== Statuses.DECLINED">
|
<li v-if="status !== Statuses.DECLINED">
|
||||||
<a class="dropdown-item" @click="changeStatus(Statuses.DECLINED)"
|
<a
|
||||||
><i class="fa fa-times" aria-hidden="true"></i> {{ $t("Decline") }}</a
|
class="dropdown-item"
|
||||||
|
@click="changeStatus(Statuses.DECLINED)"
|
||||||
|
><i class="fa fa-times" aria-hidden="true"></i>
|
||||||
|
{{ $t("Decline") }}</a
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="status !== Statuses.TENTATIVELY_ACCEPTED">
|
<li v-if="status !== Statuses.TENTATIVELY_ACCEPTED">
|
||||||
<a
|
<a
|
||||||
class="dropdown-item"
|
class="dropdown-item"
|
||||||
@click="changeStatus(Statuses.TENTATIVELY_ACCEPTED)"
|
@click="changeStatus(Statuses.TENTATIVELY_ACCEPTED)"
|
||||||
><i class="fa fa-question"></i> {{ $t("Tentatively_accept") }}</a
|
><i class="fa fa-question"></i>
|
||||||
|
{{ $t("Tentatively_accept") }}</a
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="status !== Statuses.PENDING">
|
<li v-if="status !== Statuses.PENDING">
|
||||||
<a class="dropdown-item" @click="changeStatus(Statuses.PENDING)"
|
<a class="dropdown-item" @click="changeStatus(Statuses.PENDING)"
|
||||||
><i class="fa fa-hourglass-o"></i> {{ $t("Set_pending") }}</a
|
><i class="fa fa-hourglass-o"></i>
|
||||||
|
{{ $t("Set_pending") }}</a
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -83,7 +91,9 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
emits: {
|
emits: {
|
||||||
statusChanged(payload: "accepted" | "declined" | "pending" | "tentative") {
|
statusChanged(
|
||||||
|
payload: "accepted" | "declined" | "pending" | "tentative",
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@@ -23,14 +23,24 @@
|
|||||||
<label class="input-group-text" for="slotDuration"
|
<label class="input-group-text" for="slotDuration"
|
||||||
>Durée des créneaux</label
|
>Durée des créneaux</label
|
||||||
>
|
>
|
||||||
<select v-model="slotDuration" id="slotDuration" class="form-select">
|
<select
|
||||||
|
v-model="slotDuration"
|
||||||
|
id="slotDuration"
|
||||||
|
class="form-select"
|
||||||
|
>
|
||||||
<option value="00:05:00">5 minutes</option>
|
<option value="00:05:00">5 minutes</option>
|
||||||
<option value="00:10:00">10 minutes</option>
|
<option value="00:10:00">10 minutes</option>
|
||||||
<option value="00:15:00">15 minutes</option>
|
<option value="00:15:00">15 minutes</option>
|
||||||
<option value="00:30:00">30 minutes</option>
|
<option value="00:30:00">30 minutes</option>
|
||||||
|
<option value="00:45:00">45 minutes</option>
|
||||||
|
<option value="00:60:00">60 minutes</option>
|
||||||
</select>
|
</select>
|
||||||
<label class="input-group-text" for="slotMinTime">De</label>
|
<label class="input-group-text" for="slotMinTime">De</label>
|
||||||
<select v-model="slotMinTime" id="slotMinTime" class="form-select">
|
<select
|
||||||
|
v-model="slotMinTime"
|
||||||
|
id="slotMinTime"
|
||||||
|
class="form-select"
|
||||||
|
>
|
||||||
<option value="00:00:00">0h</option>
|
<option value="00:00:00">0h</option>
|
||||||
<option value="01:00:00">1h</option>
|
<option value="01:00:00">1h</option>
|
||||||
<option value="02:00:00">2h</option>
|
<option value="02:00:00">2h</option>
|
||||||
@@ -46,7 +56,11 @@
|
|||||||
<option value="12:00:00">12h</option>
|
<option value="12:00:00">12h</option>
|
||||||
</select>
|
</select>
|
||||||
<label class="input-group-text" for="slotMaxTime">À</label>
|
<label class="input-group-text" for="slotMaxTime">À</label>
|
||||||
<select v-model="slotMaxTime" id="slotMaxTime" class="form-select">
|
<select
|
||||||
|
v-model="slotMaxTime"
|
||||||
|
id="slotMaxTime"
|
||||||
|
class="form-select"
|
||||||
|
>
|
||||||
<option value="12:00:00">12h</option>
|
<option value="12:00:00">12h</option>
|
||||||
<option value="13:00:00">13h</option>
|
<option value="13:00:00">13h</option>
|
||||||
<option value="14:00:00">14h</option>
|
<option value="14:00:00">14h</option>
|
||||||
@@ -74,7 +88,9 @@
|
|||||||
v-model="showWeekends"
|
v-model="showWeekends"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<label for="showHideWE" class="form-check-label input-group-text"
|
<label
|
||||||
|
for="showHideWE"
|
||||||
|
class="form-check-label input-group-text"
|
||||||
>Week-ends</label
|
>Week-ends</label
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
@@ -84,12 +100,17 @@
|
|||||||
<FullCalendar :options="calendarOptions" ref="calendarRef">
|
<FullCalendar :options="calendarOptions" ref="calendarRef">
|
||||||
<template v-slot:eventContent="{ event }: { event: EventApi }">
|
<template v-slot:eventContent="{ event }: { event: EventApi }">
|
||||||
<span :class="eventClasses">
|
<span :class="eventClasses">
|
||||||
<b v-if="event.extendedProps.is === 'remote'">{{ event.title }}</b>
|
<b v-if="event.extendedProps.is === 'remote'">{{
|
||||||
|
event.title
|
||||||
|
}}</b>
|
||||||
<b v-else-if="event.extendedProps.is === 'range'"
|
<b v-else-if="event.extendedProps.is === 'range'"
|
||||||
>{{ formatDate(event.startStr) }} -
|
>{{ formatDate(event.startStr, "time") }} -
|
||||||
|
{{ formatDate(event.endStr, "time") }}:
|
||||||
{{ event.extendedProps.locationName }}</b
|
{{ event.extendedProps.locationName }}</b
|
||||||
>
|
>
|
||||||
<b v-else-if="event.extendedProps.is === 'local'">{{ event.title }}</b>
|
<b v-else-if="event.extendedProps.is === 'local'">{{
|
||||||
|
event.title
|
||||||
|
}}</b>
|
||||||
<b v-else>no 'is'</b>
|
<b v-else>no 'is'</b>
|
||||||
<a
|
<a
|
||||||
v-if="event.extendedProps.is === 'range'"
|
v-if="event.extendedProps.is === 'range'"
|
||||||
@@ -108,7 +129,11 @@
|
|||||||
<h6 class="chill-red">{{ $t("copy_range_from_to") }}</h6>
|
<h6 class="chill-red">{{ $t("copy_range_from_to") }}</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-sm-9 col-md-2">
|
<div class="col-xs-12 col-sm-9 col-md-2">
|
||||||
<select v-model="dayOrWeek" id="dayOrWeek" class="form-select">
|
<select
|
||||||
|
v-model="dayOrWeek"
|
||||||
|
id="dayOrWeek"
|
||||||
|
class="form-select"
|
||||||
|
>
|
||||||
<option value="day">{{ $t("from_day_to_day") }}</option>
|
<option value="day">{{ $t("from_day_to_day") }}</option>
|
||||||
<option value="week">
|
<option value="week">
|
||||||
{{ $t("from_week_to_week") }}
|
{{ $t("from_week_to_week") }}
|
||||||
@@ -117,16 +142,27 @@
|
|||||||
</div>
|
</div>
|
||||||
<template v-if="dayOrWeek === 'day'">
|
<template v-if="dayOrWeek === 'day'">
|
||||||
<div class="col-xs-12 col-sm-3 col-md-3">
|
<div class="col-xs-12 col-sm-3 col-md-3">
|
||||||
<input class="form-control" type="date" v-model="copyFrom" />
|
<input
|
||||||
|
class="form-control"
|
||||||
|
type="date"
|
||||||
|
v-model="copyFrom"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-sm-1 col-md-1 copy-chevron">
|
<div class="col-xs-12 col-sm-1 col-md-1 copy-chevron">
|
||||||
<i class="fa fa-angle-double-right"></i>
|
<i class="fa fa-angle-double-right"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-sm-3 col-md-3">
|
<div class="col-xs-12 col-sm-3 col-md-3">
|
||||||
<input class="form-control" type="date" v-model="copyTo" />
|
<input
|
||||||
|
class="form-control"
|
||||||
|
type="date"
|
||||||
|
v-model="copyTo"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-sm-5 col-md-1">
|
<div class="col-xs-12 col-sm-5 col-md-1">
|
||||||
<button class="btn btn-action float-end" @click="copyDay">
|
<button
|
||||||
|
class="btn btn-action float-end"
|
||||||
|
@click="copyDay"
|
||||||
|
>
|
||||||
{{ $t("copy_range") }}
|
{{ $t("copy_range") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -138,7 +174,11 @@
|
|||||||
id="copyFromWeek"
|
id="copyFromWeek"
|
||||||
class="form-select"
|
class="form-select"
|
||||||
>
|
>
|
||||||
<option v-for="w in lastWeeks" :value="w.value" :key="w.value">
|
<option
|
||||||
|
v-for="w in lastWeeks"
|
||||||
|
:value="w.value"
|
||||||
|
:key="w.value"
|
||||||
|
>
|
||||||
{{ w.text }}
|
{{ w.text }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -147,14 +187,25 @@
|
|||||||
<i class="fa fa-angle-double-right"></i>
|
<i class="fa fa-angle-double-right"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-sm-3 col-md-3">
|
<div class="col-xs-12 col-sm-3 col-md-3">
|
||||||
<select v-model="copyToWeek" id="copyToWeek" class="form-select">
|
<select
|
||||||
<option v-for="w in nextWeeks" :value="w.value" :key="w.value">
|
v-model="copyToWeek"
|
||||||
|
id="copyToWeek"
|
||||||
|
class="form-select"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="w in nextWeeks"
|
||||||
|
:value="w.value"
|
||||||
|
:key="w.value"
|
||||||
|
>
|
||||||
{{ w.text }}
|
{{ w.text }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-sm-5 col-md-1">
|
<div class="col-xs-12 col-sm-5 col-md-1">
|
||||||
<button class="btn btn-action float-end" @click="copyWeek">
|
<button
|
||||||
|
class="btn btn-action float-end"
|
||||||
|
@click="copyWeek"
|
||||||
|
>
|
||||||
{{ $t("copy_range") }}
|
{{ $t("copy_range") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -246,9 +297,26 @@ const nextWeeks = computed((): Weeks[] =>
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const formatDate = (datetime: string) => {
|
const formatDate = (datetime: string, format: null | "time" = null) => {
|
||||||
console.log(typeof datetime);
|
const date = ISOToDate(datetime);
|
||||||
return ISOToDate(datetime);
|
if (!date) return "";
|
||||||
|
|
||||||
|
if (format === "time") {
|
||||||
|
return date.toLocaleTimeString("fr-FR", {
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// French date formatting
|
||||||
|
return date.toLocaleDateString("fr-FR", {
|
||||||
|
weekday: "short",
|
||||||
|
year: "numeric",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const baseOptions = ref<CalendarOptions>({
|
const baseOptions = ref<CalendarOptions>({
|
||||||
|
@@ -41,7 +41,9 @@ const futureStore = function (): Promise<Store<State>> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
store.commit("me/setWhoAmi", user, { root: true });
|
store.commit("me/setWhoAmi", user, { root: true });
|
||||||
store.dispatch("locations/getLocations", null, { root: true }).then((_) => {
|
store
|
||||||
|
.dispatch("locations/getLocations", null, { root: true })
|
||||||
|
.then((_) => {
|
||||||
return store.dispatch("locations/getCurrentLocation", null, {
|
return store.dispatch("locations/getCurrentLocation", null, {
|
||||||
root: true,
|
root: true,
|
||||||
});
|
});
|
||||||
|
@@ -29,7 +29,10 @@ export default {
|
|||||||
(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 (start.getTime() === range.start && end.getTime() === range.end) {
|
if (
|
||||||
|
start.getTime() === range.start &&
|
||||||
|
end.getTime() === range.end
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,7 +54,10 @@ export default {
|
|||||||
});
|
});
|
||||||
state.key = state.key + toAdd.length;
|
state.key = state.key + toAdd.length;
|
||||||
},
|
},
|
||||||
addLoaded(state: CalendarLocalsState, payload: { start: Date; end: Date }) {
|
addLoaded(
|
||||||
|
state: CalendarLocalsState,
|
||||||
|
payload: { start: Date; end: Date },
|
||||||
|
) {
|
||||||
state.localsLoaded.push({
|
state.localsLoaded.push({
|
||||||
start: payload.start.getTime(),
|
start: payload.start.getTime(),
|
||||||
end: payload.end.getTime(),
|
end: payload.end.getTime(),
|
||||||
@@ -79,7 +85,11 @@ export default {
|
|||||||
end: end,
|
end: end,
|
||||||
});
|
});
|
||||||
|
|
||||||
return fetchCalendarLocalForUser(ctx.rootGetters["me/getMe"], start, end)
|
return fetchCalendarLocalForUser(
|
||||||
|
ctx.rootGetters["me/getMe"],
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
)
|
||||||
.then((remotes: CalendarLight[]) => {
|
.then((remotes: CalendarLight[]) => {
|
||||||
// to be add when reactivity problem will be solve ?
|
// to be add when reactivity problem will be solve ?
|
||||||
//ctx.commit('addRemotes', remotes);
|
//ctx.commit('addRemotes', remotes);
|
||||||
|
@@ -40,7 +40,10 @@ export default {
|
|||||||
(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 (start.getTime() === range.start && end.getTime() === range.end) {
|
if (
|
||||||
|
start.getTime() === range.start &&
|
||||||
|
end.getTime() === range.end
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,7 +110,9 @@ export default {
|
|||||||
state: CalendarRangesState,
|
state: CalendarRangesState,
|
||||||
externalEvents: (EventInput & { id: string })[],
|
externalEvents: (EventInput & { id: string })[],
|
||||||
) {
|
) {
|
||||||
const toAdd = externalEvents.filter((r) => !state.rangesIndex.has(r.id));
|
const toAdd = externalEvents.filter(
|
||||||
|
(r) => !state.rangesIndex.has(r.id),
|
||||||
|
);
|
||||||
|
|
||||||
toAdd.forEach((r) => {
|
toAdd.forEach((r) => {
|
||||||
state.rangesIndex.add(r.id);
|
state.rangesIndex.add(r.id);
|
||||||
@@ -115,7 +120,10 @@ export default {
|
|||||||
});
|
});
|
||||||
state.key = state.key + toAdd.length;
|
state.key = state.key + toAdd.length;
|
||||||
},
|
},
|
||||||
addLoaded(state: CalendarRangesState, payload: { start: Date; end: Date }) {
|
addLoaded(
|
||||||
|
state: CalendarRangesState,
|
||||||
|
payload: { start: Date; end: Date },
|
||||||
|
) {
|
||||||
state.rangesLoaded.push({
|
state.rangesLoaded.push({
|
||||||
start: payload.start.getTime(),
|
start: payload.start.getTime(),
|
||||||
end: payload.end.getTime(),
|
end: payload.end.getTime(),
|
||||||
@@ -134,12 +142,17 @@ export default {
|
|||||||
},
|
},
|
||||||
removeRange(state: CalendarRangesState, calendarRangeId: number) {
|
removeRange(state: CalendarRangesState, calendarRangeId: number) {
|
||||||
const found = state.ranges.find(
|
const found = state.ranges.find(
|
||||||
(r) => r.calendarRangeId === calendarRangeId && r.is === "range",
|
(r) =>
|
||||||
|
r.calendarRangeId === calendarRangeId && r.is === "range",
|
||||||
);
|
);
|
||||||
|
|
||||||
if (found !== undefined) {
|
if (found !== undefined) {
|
||||||
state.ranges = state.ranges.filter(
|
state.ranges = state.ranges.filter(
|
||||||
(r) => !(r.calendarRangeId === calendarRangeId && r.is === "range"),
|
(r) =>
|
||||||
|
!(
|
||||||
|
r.calendarRangeId === calendarRangeId &&
|
||||||
|
r.is === "range"
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (typeof found.id === "string") {
|
if (typeof found.id === "string") {
|
||||||
@@ -198,7 +211,11 @@ export default {
|
|||||||
},
|
},
|
||||||
createRange(
|
createRange(
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
{ start, end, location }: { start: Date; end: Date; location: Location },
|
{
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
location,
|
||||||
|
}: { start: Date; end: Date; location: Location },
|
||||||
): Promise<null> {
|
): Promise<null> {
|
||||||
const url = `/api/1.0/calendar/calendar-range.json?`;
|
const url = `/api/1.0/calendar/calendar-range.json?`;
|
||||||
|
|
||||||
@@ -223,7 +240,11 @@ export default {
|
|||||||
},
|
},
|
||||||
} as CalendarRangeCreate;
|
} as CalendarRangeCreate;
|
||||||
|
|
||||||
return makeFetch<CalendarRangeCreate, CalendarRange>("POST", url, body)
|
return makeFetch<CalendarRangeCreate, CalendarRange>(
|
||||||
|
"POST",
|
||||||
|
url,
|
||||||
|
body,
|
||||||
|
)
|
||||||
.then((newRange) => {
|
.then((newRange) => {
|
||||||
ctx.commit("addRange", newRange);
|
ctx.commit("addRange", newRange);
|
||||||
|
|
||||||
@@ -260,7 +281,11 @@ export default {
|
|||||||
},
|
},
|
||||||
} as CalendarRangeEdit;
|
} as CalendarRangeEdit;
|
||||||
|
|
||||||
return makeFetch<CalendarRangeEdit, CalendarRange>("PATCH", url, body)
|
return makeFetch<CalendarRangeEdit, CalendarRange>(
|
||||||
|
"PATCH",
|
||||||
|
url,
|
||||||
|
body,
|
||||||
|
)
|
||||||
.then((range) => {
|
.then((range) => {
|
||||||
ctx.commit("updateRange", range);
|
ctx.commit("updateRange", range);
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
@@ -285,7 +310,11 @@ export default {
|
|||||||
},
|
},
|
||||||
} as CalendarRangeEdit;
|
} as CalendarRangeEdit;
|
||||||
|
|
||||||
return makeFetch<CalendarRangeEdit, CalendarRange>("PATCH", url, body)
|
return makeFetch<CalendarRangeEdit, CalendarRange>(
|
||||||
|
"PATCH",
|
||||||
|
url,
|
||||||
|
body,
|
||||||
|
)
|
||||||
.then((range) => {
|
.then((range) => {
|
||||||
ctx.commit("updateRange", range);
|
ctx.commit("updateRange", range);
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
@@ -305,14 +334,20 @@ export default {
|
|||||||
|
|
||||||
for (const r of rangesToCopy) {
|
for (const r of rangesToCopy) {
|
||||||
const start = new Date(ISOToDatetime(r.start) as Date);
|
const start = new Date(ISOToDatetime(r.start) as Date);
|
||||||
start.setFullYear(to.getFullYear(), to.getMonth(), to.getDate());
|
start.setFullYear(
|
||||||
|
to.getFullYear(),
|
||||||
|
to.getMonth(),
|
||||||
|
to.getDate(),
|
||||||
|
);
|
||||||
const end = new Date(ISOToDatetime(r.end) as Date);
|
const end = new Date(ISOToDatetime(r.end) as Date);
|
||||||
end.setFullYear(to.getFullYear(), to.getMonth(), to.getDate());
|
end.setFullYear(to.getFullYear(), to.getMonth(), to.getDate());
|
||||||
const location = ctx.rootGetters["locations/getLocationById"](
|
const location = ctx.rootGetters["locations/getLocationById"](
|
||||||
r.locationId,
|
r.locationId,
|
||||||
);
|
);
|
||||||
|
|
||||||
promises.push(ctx.dispatch("createRange", { start, end, location }));
|
promises.push(
|
||||||
|
ctx.dispatch("createRange", { start, end, location }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(promises).then(() => Promise.resolve(null));
|
return Promise.all(promises).then(() => Promise.resolve(null));
|
||||||
@@ -334,7 +369,9 @@ export default {
|
|||||||
r.locationId,
|
r.locationId,
|
||||||
);
|
);
|
||||||
|
|
||||||
promises.push(ctx.dispatch("createRange", { start, end, location }));
|
promises.push(
|
||||||
|
ctx.dispatch("createRange", { start, end, location }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(promises).then(() => Promise.resolve(null));
|
return Promise.all(promises).then(() => Promise.resolve(null));
|
||||||
|
@@ -29,7 +29,10 @@ export default {
|
|||||||
(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 (start.getTime() === range.start && end.getTime() === range.end) {
|
if (
|
||||||
|
start.getTime() === range.start &&
|
||||||
|
end.getTime() === range.end
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,7 +85,11 @@ export default {
|
|||||||
end: end,
|
end: end,
|
||||||
});
|
});
|
||||||
|
|
||||||
return fetchCalendarRemoteForUser(ctx.rootGetters["me/getMe"], start, end)
|
return fetchCalendarRemoteForUser(
|
||||||
|
ctx.rootGetters["me/getMe"],
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
)
|
||||||
.then((remotes: CalendarRemote[]) => {
|
.then((remotes: CalendarRemote[]) => {
|
||||||
// to be add when reactivity problem will be solve ?
|
// to be add when reactivity problem will be solve ?
|
||||||
//ctx.commit('addRemotes', remotes);
|
//ctx.commit('addRemotes', remotes);
|
||||||
|
@@ -112,8 +112,11 @@ export default {
|
|||||||
|
|
||||||
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(users.length / COLORS.length);
|
let ratio = Math.floor(
|
||||||
let colorIndex = users.length - ratio * COLORS.length;
|
users.length / COLORS.length,
|
||||||
|
);
|
||||||
|
let colorIndex =
|
||||||
|
users.length - ratio * COLORS.length;
|
||||||
users.push({
|
users.push({
|
||||||
id: i.user.id,
|
id: i.user.id,
|
||||||
username: i.user.username,
|
username: i.user.username,
|
||||||
@@ -150,29 +153,45 @@ export default {
|
|||||||
(me) =>
|
(me) =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
this.users.logged = me;
|
this.users.logged = me;
|
||||||
let currentUser = users.find((u) => u.id === me.id);
|
let currentUser = users.find(
|
||||||
|
(u) => u.id === me.id,
|
||||||
|
);
|
||||||
this.value = currentUser;
|
this.value = currentUser;
|
||||||
|
|
||||||
fetchCalendar(currentUser.id).then(
|
fetchCalendar(currentUser.id).then(
|
||||||
(calendar) =>
|
(calendar) =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise(
|
||||||
let results = calendar.results;
|
(resolve, reject) => {
|
||||||
let events = results.map((i) => ({
|
let results =
|
||||||
start: i.startDate.datetime,
|
calendar.results;
|
||||||
end: i.endDate.datetime,
|
let events =
|
||||||
}));
|
results.map(
|
||||||
let calendarEventsCurrentUser = {
|
(i) => ({
|
||||||
|
start: i
|
||||||
|
.startDate
|
||||||
|
.datetime,
|
||||||
|
end: i
|
||||||
|
.endDate
|
||||||
|
.datetime,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
let calendarEventsCurrentUser =
|
||||||
|
{
|
||||||
events: events,
|
events: events,
|
||||||
color: "darkblue",
|
color: "darkblue",
|
||||||
id: 1000,
|
id: 1000,
|
||||||
editable: false,
|
editable: false,
|
||||||
};
|
};
|
||||||
this.calendarEvents.user = calendarEventsCurrentUser;
|
this.calendarEvents.user =
|
||||||
|
calendarEventsCurrentUser;
|
||||||
|
|
||||||
this.selectUsers(currentUser);
|
this.selectUsers(
|
||||||
|
currentUser,
|
||||||
|
);
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
@@ -190,7 +209,9 @@ export default {
|
|||||||
return `${value.username}`;
|
return `${value.username}`;
|
||||||
},
|
},
|
||||||
coloriseSelectedValues() {
|
coloriseSelectedValues() {
|
||||||
let tags = document.querySelectorAll("div.multiselect__tags-wrap")[0];
|
let tags = document.querySelectorAll(
|
||||||
|
"div.multiselect__tags-wrap",
|
||||||
|
)[0];
|
||||||
|
|
||||||
if (tags.hasChildNodes()) {
|
if (tags.hasChildNodes()) {
|
||||||
let children = tags.childNodes;
|
let children = tags.childNodes;
|
||||||
@@ -211,8 +232,8 @@ export default {
|
|||||||
},
|
},
|
||||||
selectEvents() {
|
selectEvents() {
|
||||||
let selectedUsersId = this.users.selected.map((a) => a.id);
|
let selectedUsersId = this.users.selected.map((a) => a.id);
|
||||||
this.calendarEvents.selected = this.calendarEvents.loaded.filter((a) =>
|
this.calendarEvents.selected = this.calendarEvents.loaded.filter(
|
||||||
selectedUsersId.includes(a.id),
|
(a) => selectedUsersId.includes(a.id),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
selectUsers(value) {
|
selectUsers(value) {
|
||||||
@@ -222,7 +243,9 @@ export default {
|
|||||||
this.updateEventsSource();
|
this.updateEventsSource();
|
||||||
},
|
},
|
||||||
unSelectUsers(value) {
|
unSelectUsers(value) {
|
||||||
this.users.selected = this.users.selected.filter((a) => a.id != value.id);
|
this.users.selected = this.users.selected.filter(
|
||||||
|
(a) => a.id != value.id,
|
||||||
|
);
|
||||||
this.selectEvents();
|
this.selectEvents();
|
||||||
this.updateEventsSource();
|
this.updateEventsSource();
|
||||||
},
|
},
|
||||||
|
@@ -20,7 +20,10 @@
|
|||||||
</option>
|
</option>
|
||||||
<template v-for="t in templates" :key="t.id">
|
<template v-for="t in templates" :key="t.id">
|
||||||
<option :value="t.id">
|
<option :value="t.id">
|
||||||
{{ localizeString(t.name) || "Aucun nom défini" }}
|
{{
|
||||||
|
localizeString(t.name) ||
|
||||||
|
"Aucun nom défini"
|
||||||
|
}}
|
||||||
</option>
|
</option>
|
||||||
</template>
|
</template>
|
||||||
</select>
|
</select>
|
||||||
@@ -28,7 +31,9 @@
|
|||||||
v-if="canGenerate"
|
v-if="canGenerate"
|
||||||
class="btn btn-update btn-sm change-icon"
|
class="btn btn-update btn-sm change-icon"
|
||||||
:href="buildUrlGenerate"
|
:href="buildUrlGenerate"
|
||||||
@click.prevent="clickGenerate($event, buildUrlGenerate)"
|
@click.prevent="
|
||||||
|
clickGenerate($event, buildUrlGenerate)
|
||||||
|
"
|
||||||
><i class="fa fa-fw fa-cog"
|
><i class="fa fa-fw fa-cog"
|
||||||
/></a>
|
/></a>
|
||||||
<a
|
<a
|
||||||
|
@@ -94,7 +94,7 @@ class StoredObject implements Document, TrackCreationInterface
|
|||||||
/**
|
/**
|
||||||
* @var Collection<int, StoredObjectVersion>&Selectable<int, StoredObjectVersion>
|
* @var Collection<int, StoredObjectVersion>&Selectable<int, StoredObjectVersion>
|
||||||
*/
|
*/
|
||||||
#[ORM\OneToMany(mappedBy: 'storedObject', targetEntity: StoredObjectVersion::class, cascade: ['persist'], orphanRemoval: true, fetch: 'EAGER')]
|
#[ORM\OneToMany(mappedBy: 'storedObject', targetEntity: StoredObjectVersion::class, cascade: ['persist'], orphanRemoval: true)]
|
||||||
private Collection&Selectable $versions;
|
private Collection&Selectable $versions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -13,9 +13,8 @@ const startApp = (
|
|||||||
|
|
||||||
const inputTitle = collectionEntry?.querySelector("input[type='text']");
|
const inputTitle = collectionEntry?.querySelector("input[type='text']");
|
||||||
|
|
||||||
const input_stored_object: HTMLInputElement | null = divElement.querySelector(
|
const input_stored_object: HTMLInputElement | null =
|
||||||
"input[data-stored-object]",
|
divElement.querySelector("input[data-stored-object]");
|
||||||
);
|
|
||||||
if (null === input_stored_object) {
|
if (null === input_stored_object) {
|
||||||
throw new Error("input to stored object not found");
|
throw new Error("input to stored object not found");
|
||||||
}
|
}
|
||||||
@@ -54,7 +53,9 @@ const startApp = (
|
|||||||
console.log("version added", stored_object_version);
|
console.log("version added", stored_object_version);
|
||||||
this.$data.existingDoc = stored_object;
|
this.$data.existingDoc = stored_object;
|
||||||
this.$data.existingDoc.currentVersion = stored_object_version;
|
this.$data.existingDoc.currentVersion = stored_object_version;
|
||||||
input_stored_object.value = JSON.stringify(this.$data.existingDoc);
|
input_stored_object.value = JSON.stringify(
|
||||||
|
this.$data.existingDoc,
|
||||||
|
);
|
||||||
if (this.$data.inputTitle) {
|
if (this.$data.inputTitle) {
|
||||||
if (!this.$data.inputTitle?.value) {
|
if (!this.$data.inputTitle?.value) {
|
||||||
this.$data.inputTitle.value = file_name;
|
this.$data.inputTitle.value = file_name;
|
||||||
|
@@ -49,7 +49,9 @@
|
|||||||
<li v-if="isHistoryViewable">
|
<li v-if="isHistoryViewable">
|
||||||
<history-button
|
<history-button
|
||||||
:stored-object="props.storedObject"
|
:stored-object="props.storedObject"
|
||||||
:can-edit="canEdit && props.storedObject._permissions.canEdit"
|
:can-edit="
|
||||||
|
canEdit && props.storedObject._permissions.canEdit
|
||||||
|
"
|
||||||
></history-button>
|
></history-button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -127,7 +129,9 @@ const props = withDefaults(defineProps<DocumentActionButtonsGroupConfig>(), {
|
|||||||
canDownload: true,
|
canDownload: true,
|
||||||
canConvertPdf: true,
|
canConvertPdf: true,
|
||||||
returnPath:
|
returnPath:
|
||||||
window.location.pathname + window.location.search + window.location.hash,
|
window.location.pathname +
|
||||||
|
window.location.search +
|
||||||
|
window.location.hash,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -29,7 +29,9 @@
|
|||||||
</modal>
|
</modal>
|
||||||
</teleport>
|
</teleport>
|
||||||
<div class="col-12 m-auto sticky-top">
|
<div class="col-12 m-auto sticky-top">
|
||||||
<div class="row justify-content-center border-bottom pdf-tools d-md-none">
|
<div
|
||||||
|
class="row justify-content-center border-bottom pdf-tools d-md-none"
|
||||||
|
>
|
||||||
<div class="col-5 text-center turn-page">
|
<div class="col-5 text-center turn-page">
|
||||||
<select
|
<select
|
||||||
class="form-select form-select-sm"
|
class="form-select form-select-sm"
|
||||||
@@ -90,7 +92,10 @@
|
|||||||
v-if="signature.zones.length === 1 && signedState !== 'signed'"
|
v-if="signature.zones.length === 1 && signedState !== 'signed'"
|
||||||
class="col-5 p-0 text-center turnSignature"
|
class="col-5 p-0 text-center turnSignature"
|
||||||
>
|
>
|
||||||
<button class="btn btn-light btn-sm" @click="goToSignatureZoneUnique">
|
<button
|
||||||
|
class="btn btn-light btn-sm"
|
||||||
|
@click="goToSignatureZoneUnique"
|
||||||
|
>
|
||||||
{{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
|
{{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -145,7 +150,10 @@
|
|||||||
:title="trans(SIGNATURES_ADD_SIGN_ZONE)"
|
:title="trans(SIGNATURES_ADD_SIGN_ZONE)"
|
||||||
>
|
>
|
||||||
<template v-if="canvasEvent === 'add'">
|
<template v-if="canvasEvent === 'add'">
|
||||||
<div class="spinner-border spinner-border-sm" role="status">
|
<div
|
||||||
|
class="spinner-border spinner-border-sm"
|
||||||
|
role="status"
|
||||||
|
>
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span class="visually-hidden">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -199,7 +207,10 @@
|
|||||||
v-if="signature.zones.length === 1 && signedState !== 'signed'"
|
v-if="signature.zones.length === 1 && signedState !== 'signed'"
|
||||||
class="col-4 d-xl-none text-center turnSignature p-0"
|
class="col-4 d-xl-none text-center turnSignature p-0"
|
||||||
>
|
>
|
||||||
<button class="btn btn-light btn-sm" @click="goToSignatureZoneUnique">
|
<button
|
||||||
|
class="btn btn-light btn-sm"
|
||||||
|
@click="goToSignatureZoneUnique"
|
||||||
|
>
|
||||||
{{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
|
{{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -227,7 +238,10 @@
|
|||||||
v-if="signature.zones.length === 1 && signedState !== 'signed'"
|
v-if="signature.zones.length === 1 && signedState !== 'signed'"
|
||||||
class="col-4 d-none d-xl-flex p-0 text-center turnSignature"
|
class="col-4 d-none d-xl-flex p-0 text-center turnSignature"
|
||||||
>
|
>
|
||||||
<button class="btn btn-light btn-sm" @click="goToSignatureZoneUnique">
|
<button
|
||||||
|
class="btn btn-light btn-sm"
|
||||||
|
@click="goToSignatureZoneUnique"
|
||||||
|
>
|
||||||
{{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
|
{{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -285,7 +299,10 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ trans(SIGNATURES_CLICK_ON_DOCUMENT) }}
|
{{ trans(SIGNATURES_CLICK_ON_DOCUMENT) }}
|
||||||
<div class="spinner-border spinner-border-sm" role="status">
|
<div
|
||||||
|
class="spinner-border spinner-border-sm"
|
||||||
|
role="status"
|
||||||
|
>
|
||||||
<span class="visually-hidden">Loading...</span>
|
<span class="visually-hidden">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -545,8 +562,14 @@ const addCanvasEvents = () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const canvas = document.querySelectorAll("canvas")[0] as HTMLCanvasElement;
|
const canvas = document.querySelectorAll(
|
||||||
canvas.addEventListener("pointerup", (e) => canvasClick(e, canvas), false);
|
"canvas",
|
||||||
|
)[0] as HTMLCanvasElement;
|
||||||
|
canvas.addEventListener(
|
||||||
|
"pointerup",
|
||||||
|
(e) => canvasClick(e, canvas),
|
||||||
|
false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -582,7 +605,11 @@ const hitSignature = (
|
|||||||
scaleYToCanvas(zone.y, canvas.height, zone.PDFPage.height) <
|
scaleYToCanvas(zone.y, canvas.height, zone.PDFPage.height) <
|
||||||
xy[1] &&
|
xy[1] &&
|
||||||
xy[1] <
|
xy[1] <
|
||||||
scaleYToCanvas(zone.height - zone.y, canvas.height, zone.PDFPage.height) +
|
scaleYToCanvas(
|
||||||
|
zone.height - zone.y,
|
||||||
|
canvas.height,
|
||||||
|
zone.PDFPage.height,
|
||||||
|
) +
|
||||||
zone.PDFPage.height * zoom.value;
|
zone.PDFPage.height * zoom.value;
|
||||||
|
|
||||||
const selectZone = async (z: SignatureZone, canvas: HTMLCanvasElement) => {
|
const selectZone = async (z: SignatureZone, canvas: HTMLCanvasElement) => {
|
||||||
@@ -598,7 +625,8 @@ const selectZoneEvent = (e: PointerEvent, canvas: HTMLCanvasElement) =>
|
|||||||
signature.zones
|
signature.zones
|
||||||
.filter(
|
.filter(
|
||||||
(z) =>
|
(z) =>
|
||||||
(z.PDFPage.index + 1 === getCanvasId(canvas) && multiPage.value) ||
|
(z.PDFPage.index + 1 === getCanvasId(canvas) &&
|
||||||
|
multiPage.value) ||
|
||||||
(z.PDFPage.index + 1 === page.value && !multiPage.value),
|
(z.PDFPage.index + 1 === page.value && !multiPage.value),
|
||||||
)
|
)
|
||||||
.map((z) => {
|
.map((z) => {
|
||||||
|
@@ -153,10 +153,12 @@ const handleFile = async (file: File): Promise<void> => {
|
|||||||
</p>
|
</p>
|
||||||
<!-- todo i18n -->
|
<!-- todo i18n -->
|
||||||
<p v-if="has_existing_doc">
|
<p v-if="has_existing_doc">
|
||||||
Déposez un document ou cliquez ici pour remplacer le document existant
|
Déposez un document ou cliquez ici pour remplacer le document
|
||||||
|
existant
|
||||||
</p>
|
</p>
|
||||||
<p v-else>
|
<p v-else>
|
||||||
Déposez un document ou cliquez ici pour ouvrir le navigateur de fichier
|
Déposez un document ou cliquez ici pour ouvrir le navigateur de
|
||||||
|
fichier
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="waiting">
|
<div v-else class="waiting">
|
||||||
|
@@ -4,6 +4,7 @@ import { StoredObject, StoredObjectVersion } from "../../types";
|
|||||||
import DropFileWidget from "ChillDocStoreAssets/vuejs/DropFileWidget/DropFileWidget.vue";
|
import DropFileWidget from "ChillDocStoreAssets/vuejs/DropFileWidget/DropFileWidget.vue";
|
||||||
import { computed, reactive } from "vue";
|
import { computed, reactive } from "vue";
|
||||||
import { useToast } from "vue-toast-notification";
|
import { useToast } from "vue-toast-notification";
|
||||||
|
import { DOCUMENT_ADD, trans } from "translator";
|
||||||
|
|
||||||
interface DropFileConfig {
|
interface DropFileConfig {
|
||||||
allowRemove: boolean;
|
allowRemove: boolean;
|
||||||
@@ -75,11 +76,9 @@ function closeModal(): void {
|
|||||||
@click="openModal"
|
@click="openModal"
|
||||||
class="btn btn-create"
|
class="btn btn-create"
|
||||||
>
|
>
|
||||||
Ajouter un document
|
{{ trans(DOCUMENT_ADD) }}
|
||||||
</button>
|
|
||||||
<button v-else @click="openModal" class="btn btn-edit">
|
|
||||||
Remplacer le document
|
|
||||||
</button>
|
</button>
|
||||||
|
<button v-else @click="openModal" class="btn btn-edit"></button>
|
||||||
<modal
|
<modal
|
||||||
v-if="state.showModal"
|
v-if="state.showModal"
|
||||||
:modal-dialog-class="modalClasses"
|
:modal-dialog-class="modalClasses"
|
||||||
|
@@ -35,7 +35,9 @@ async function download_and_open(event: Event): Promise<void> {
|
|||||||
if (null === state.content) {
|
if (null === state.content) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const raw = await download_doc(build_convert_link(props.storedObject.uuid));
|
const raw = await download_doc(
|
||||||
|
build_convert_link(props.storedObject.uuid),
|
||||||
|
);
|
||||||
state.content = window.URL.createObjectURL(raw);
|
state.content = window.URL.createObjectURL(raw);
|
||||||
|
|
||||||
button.href = window.URL.createObjectURL(raw);
|
button.href = window.URL.createObjectURL(raw);
|
||||||
|
@@ -42,7 +42,9 @@ const editionUntilFormatted = computed<string>(() => {
|
|||||||
<modal v-if="state.modalOpened" @close="state.modalOpened = false">
|
<modal v-if="state.modalOpened" @close="state.modalOpened = false">
|
||||||
<template v-slot:body>
|
<template v-slot:body>
|
||||||
<div class="desktop-edit">
|
<div class="desktop-edit">
|
||||||
<p class="center">Veuillez enregistrer vos modifications avant le</p>
|
<p class="center">
|
||||||
|
Veuillez enregistrer vos modifications avant le
|
||||||
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<strong>{{ editionUntilFormatted }}</strong>
|
<strong>{{ editionUntilFormatted }}</strong>
|
||||||
</p>
|
</p>
|
||||||
@@ -55,21 +57,23 @@ const editionUntilFormatted = computed<string>(() => {
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
<small
|
<small
|
||||||
>Le document peut être édité uniquement en utilisant Libre
|
>Le document peut être édité uniquement en utilisant
|
||||||
Office.</small
|
Libre Office.</small
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<small
|
<small
|
||||||
>En cas d'échec lors de l'enregistrement, sauver le document sur
|
>En cas d'échec lors de l'enregistrement, sauver le
|
||||||
le poste de travail avant de le déposer à nouveau ici.</small
|
document sur le poste de travail avant de le déposer
|
||||||
|
à nouveau ici.</small
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<small
|
<small
|
||||||
>Vous pouvez naviguez sur d'autres pages pendant l'édition.</small
|
>Vous pouvez naviguez sur d'autres pages pendant
|
||||||
|
l'édition.</small
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -95,7 +95,10 @@ async function download_and_open(): Promise<void> {
|
|||||||
let raw;
|
let raw;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
raw = await download_and_decrypt_doc(props.storedObject, props.atVersion);
|
raw = await download_and_decrypt_doc(
|
||||||
|
props.storedObject,
|
||||||
|
props.atVersion,
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("error while downloading and decrypting document");
|
console.error("error while downloading and decrypting document");
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
@@ -49,7 +49,8 @@ const isRestored = computed<boolean>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const isDuplicated = computed<boolean>(
|
const isDuplicated = computed<boolean>(
|
||||||
() => props.version.version === 0 && null !== props.version["from-restored"],
|
() =>
|
||||||
|
props.version.version === 0 && null !== props.version["from-restored"],
|
||||||
);
|
);
|
||||||
|
|
||||||
const classes = computed<{
|
const classes = computed<{
|
||||||
@@ -69,9 +70,16 @@ const classes = computed<{
|
|||||||
<div :class="classes">
|
<div :class="classes">
|
||||||
<div
|
<div
|
||||||
class="col-12 tags"
|
class="col-12 tags"
|
||||||
v-if="isCurrent || isKeptBeforeConversion || isRestored || isDuplicated"
|
v-if="
|
||||||
|
isCurrent ||
|
||||||
|
isKeptBeforeConversion ||
|
||||||
|
isRestored ||
|
||||||
|
isDuplicated
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span class="badge bg-success" v-if="isCurrent"
|
||||||
|
>Version actuelle</span
|
||||||
>
|
>
|
||||||
<span class="badge bg-success" v-if="isCurrent">Version actuelle</span>
|
|
||||||
<span class="badge bg-info" v-if="isKeptBeforeConversion"
|
<span class="badge bg-info" v-if="isKeptBeforeConversion"
|
||||||
>Conservée avant conversion dans un autre format</span
|
>Conservée avant conversion dans un autre format</span
|
||||||
>
|
>
|
||||||
@@ -88,17 +96,21 @@ const classes = computed<{
|
|||||||
<span
|
<span
|
||||||
><strong> #{{ version.version + 1 }} </strong></span
|
><strong> #{{ version.version + 1 }} </strong></span
|
||||||
>
|
>
|
||||||
<template v-if="version.createdBy !== null && version.createdAt !== null"
|
<template
|
||||||
|
v-if="version.createdBy !== null && version.createdAt !== null"
|
||||||
><strong v-if="version.version == 0">créé par</strong
|
><strong v-if="version.version == 0">créé par</strong
|
||||||
><strong v-else>modifié par</strong>
|
><strong v-else>modifié par</strong>
|
||||||
<span class="badge-user"
|
<span class="badge-user"
|
||||||
><UserRenderBoxBadge :user="version.createdBy"></UserRenderBoxBadge
|
><UserRenderBoxBadge
|
||||||
|
:user="version.createdBy"
|
||||||
|
></UserRenderBoxBadge
|
||||||
></span>
|
></span>
|
||||||
<strong>à</strong>
|
<strong>à</strong>
|
||||||
{{
|
{{
|
||||||
$d(ISOToDatetime(version.createdAt.datetime8601), "long")
|
$d(ISOToDatetime(version.createdAt.datetime8601), "long")
|
||||||
}}</template
|
}}</template
|
||||||
><template v-if="version.createdBy === null && version.createdAt !== null"
|
><template
|
||||||
|
v-if="version.createdBy === null && version.createdAt !== null"
|
||||||
><strong v-if="version.version == 0">Créé le</strong
|
><strong v-if="version.version == 0">Créé le</strong
|
||||||
><strong v-else>modifié le</strong>
|
><strong v-else>modifié le</strong>
|
||||||
{{
|
{{
|
||||||
|
@@ -2,7 +2,9 @@
|
|||||||
<a
|
<a
|
||||||
:class="Object.assign(props.classes, { btn: true })"
|
:class="Object.assign(props.classes, { btn: true })"
|
||||||
@click="beforeLeave($event)"
|
@click="beforeLeave($event)"
|
||||||
:href="build_wopi_editor_link(props.storedObject.uuid, props.returnPath)"
|
:href="
|
||||||
|
build_wopi_editor_link(props.storedObject.uuid, props.returnPath)
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<i class="fa fa-paragraph"></i>
|
<i class="fa fa-paragraph"></i>
|
||||||
Editer en ligne
|
Editer en ligne
|
||||||
|
@@ -145,7 +145,9 @@ async function download_info_link(
|
|||||||
function build_wopi_editor_link(uuid: string, returnPath?: string) {
|
function build_wopi_editor_link(uuid: string, returnPath?: string) {
|
||||||
if (returnPath === undefined) {
|
if (returnPath === undefined) {
|
||||||
returnPath =
|
returnPath =
|
||||||
window.location.pathname + window.location.search + window.location.hash;
|
window.location.pathname +
|
||||||
|
window.location.search +
|
||||||
|
window.location.hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -184,7 +186,10 @@ async function download_and_decrypt_doc(
|
|||||||
) {
|
) {
|
||||||
downloadInfo = storedObject._links.downloadLink;
|
downloadInfo = storedObject._links.downloadLink;
|
||||||
} else {
|
} else {
|
||||||
downloadInfo = await download_info_link(storedObject, atVersionToDownload);
|
downloadInfo = await download_info_link(
|
||||||
|
storedObject,
|
||||||
|
atVersionToDownload,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const rawResponse = await window.fetch(downloadInfo.url);
|
const rawResponse = await window.fetch(downloadInfo.url);
|
||||||
@@ -239,7 +244,10 @@ async function download_doc_as_pdf(storedObject: StoredObject): Promise<Blob> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (storedObject.currentVersion?.type === "application/pdf") {
|
if (storedObject.currentVersion?.type === "application/pdf") {
|
||||||
return download_and_decrypt_doc(storedObject, storedObject.currentVersion);
|
return download_and_decrypt_doc(
|
||||||
|
storedObject,
|
||||||
|
storedObject.currentVersion,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const convertLink = build_convert_link(storedObject.uuid);
|
const convertLink = build_convert_link(storedObject.uuid);
|
||||||
|
@@ -43,17 +43,11 @@ class StoredObjectVersionNormalizer implements NormalizerInterface, NormalizerAw
|
|||||||
'createdBy' => $this->normalizer->normalize($object->getCreatedBy(), $format, [...$context, UserNormalizer::AT_DATE => $object->getCreatedAt()]),
|
'createdBy' => $this->normalizer->normalize($object->getCreatedBy(), $format, [...$context, UserNormalizer::AT_DATE => $object->getCreatedAt()]),
|
||||||
];
|
];
|
||||||
|
|
||||||
$normalizationGroups = $context[AbstractNormalizer::GROUPS] ?? [];
|
if (in_array(self::WITH_POINT_IN_TIMES_CONTEXT, $context[AbstractNormalizer::GROUPS] ?? [], true)) {
|
||||||
|
|
||||||
if (is_string($normalizationGroups)) {
|
|
||||||
$normalizationGroups = [$normalizationGroups];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_array(self::WITH_POINT_IN_TIMES_CONTEXT, $normalizationGroups, true)) {
|
|
||||||
$data['point-in-times'] = $this->normalizer->normalize($object->getPointInTimes(), $format, $context);
|
$data['point-in-times'] = $this->normalizer->normalize($object->getPointInTimes(), $format, $context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array(self::WITH_RESTORED_CONTEXT, $normalizationGroups, true)) {
|
if (in_array(self::WITH_RESTORED_CONTEXT, $context[AbstractNormalizer::GROUPS] ?? [], true)) {
|
||||||
$data['from-restored'] = $this->normalizer->normalize($object->getCreatedFrom(), $format, [AbstractNormalizer::GROUPS => ['read']]);
|
$data['from-restored'] = $this->normalizer->normalize($object->getCreatedFrom(), $format, [AbstractNormalizer::GROUPS => ['read']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,6 +23,8 @@ See the document: Voir le document
|
|||||||
|
|
||||||
document:
|
document:
|
||||||
Any title: Aucun titre
|
Any title: Aucun titre
|
||||||
|
replace: Remplacer
|
||||||
|
Add: Ajouter un document
|
||||||
|
|
||||||
generic_doc:
|
generic_doc:
|
||||||
filter:
|
filter:
|
||||||
|
@@ -118,7 +118,7 @@
|
|||||||
|
|
||||||
{{ entity.notes|chill_print_or_message("Aucune note", 'blockquote') }}
|
{{ entity.notes|chill_print_or_message("Aucune note", 'blockquote') }}
|
||||||
{% endblock crud_content_view_details %}
|
{% endblock crud_content_view_details %}
|
||||||
|
{% block content_view_actions_duplicate_link %}{% endblock %}
|
||||||
{% block content_view_actions_back %}
|
{% block content_view_actions_back %}
|
||||||
<li class="cancel">
|
<li class="cancel">
|
||||||
<a class="btn btn-cancel" href="{{ chill_return_path_or('chill_job_report_index', { 'person': entity.person.id }) }}">
|
<a class="btn btn-cancel" href="{{ chill_return_path_or('chill_job_report_index', { 'person': entity.person.id }) }}">
|
||||||
|
@@ -46,6 +46,7 @@
|
|||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
{% endblock crud_content_view_details %}
|
{% endblock crud_content_view_details %}
|
||||||
|
{% block content_view_actions_duplicate_link %}{% endblock %}
|
||||||
|
|
||||||
{% block content_view_actions_back %}
|
{% block content_view_actions_back %}
|
||||||
<li class="cancel">
|
<li class="cancel">
|
||||||
|
@@ -206,6 +206,8 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
{% block content_view_actions_duplicate_link %}{% endblock %}
|
||||||
|
|
||||||
{% block content_view_actions_after %}
|
{% block content_view_actions_after %}
|
||||||
<li>
|
<li>
|
||||||
<a class="btn btn-misc" href="{{ chill_return_path_or('chill_crud_immersion_bilan', { 'id': entity.id, 'person_id': entity.person.id }) }}">
|
<a class="btn btn-misc" href="{{ chill_return_path_or('chill_crud_immersion_bilan', { 'id': entity.id, 'person_id': entity.person.id }) }}">
|
||||||
|
@@ -94,6 +94,7 @@
|
|||||||
|
|
||||||
|
|
||||||
{% endblock crud_content_view_details %}
|
{% endblock crud_content_view_details %}
|
||||||
|
{% block content_view_actions_duplicate_link %}{% endblock %}
|
||||||
|
|
||||||
{% block content_view_actions_back %}
|
{% block content_view_actions_back %}
|
||||||
<li class="cancel">
|
<li class="cancel">
|
||||||
|
@@ -0,0 +1,64 @@
|
|||||||
|
<?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\MainBundle\Action\User\UpdateProfile;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Notification\NotificationFlagManager;
|
||||||
|
use Chill\MainBundle\Validation\Constraint\PhonenumberConstraint;
|
||||||
|
use libphonenumber\PhoneNumber;
|
||||||
|
|
||||||
|
final class UpdateProfileCommand
|
||||||
|
{
|
||||||
|
public array $notificationFlags = [];
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
#[PhonenumberConstraint]
|
||||||
|
public ?PhoneNumber $phonenumber,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public static function create(User $user, NotificationFlagManager $flagManager): self
|
||||||
|
{
|
||||||
|
$updateProfileCommand = new self($user->getPhonenumber());
|
||||||
|
|
||||||
|
foreach ($flagManager->getAllNotificationFlagProviders() as $provider) {
|
||||||
|
$updateProfileCommand->setNotificationFlag(
|
||||||
|
$provider->getFlag(),
|
||||||
|
User::NOTIF_FLAG_IMMEDIATE_EMAIL,
|
||||||
|
$user->isNotificationSendImmediately($provider->getFlag())
|
||||||
|
);
|
||||||
|
$updateProfileCommand->setNotificationFlag(
|
||||||
|
$provider->getFlag(),
|
||||||
|
User::NOTIF_FLAG_DAILY_DIGEST,
|
||||||
|
$user->isNotificationDailyDigest($provider->getFlag())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $updateProfileCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param User::NOTIF_FLAG_IMMEDIATE_EMAIL|User::NOTIF_FLAG_DAILY_DIGEST $kind
|
||||||
|
*/
|
||||||
|
private function setNotificationFlag(string $type, string $kind, bool $value): void
|
||||||
|
{
|
||||||
|
if (!array_key_exists($type, $this->notificationFlags)) {
|
||||||
|
$this->notificationFlags[$type] = ['immediate_email' => true, 'daily_digest' => false];
|
||||||
|
}
|
||||||
|
|
||||||
|
$k = match ($kind) {
|
||||||
|
User::NOTIF_FLAG_IMMEDIATE_EMAIL => 'immediate_email',
|
||||||
|
User::NOTIF_FLAG_DAILY_DIGEST => 'daily_digest',
|
||||||
|
};
|
||||||
|
|
||||||
|
$this->notificationFlags[$type][$k] = $value;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,27 @@
|
|||||||
|
<?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\MainBundle\Action\User\UpdateProfile;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
|
||||||
|
final readonly class UpdateProfileCommandHandler
|
||||||
|
{
|
||||||
|
public function updateProfile(User $user, UpdateProfileCommand $command): void
|
||||||
|
{
|
||||||
|
$user->setPhonenumber($command->phonenumber);
|
||||||
|
|
||||||
|
foreach ($command->notificationFlags as $flag => $values) {
|
||||||
|
$user->setNotificationImmediately($flag, $values['immediate_email']);
|
||||||
|
$user->setNotificationDailyDigest($flag, $values['daily_digest']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -48,6 +48,7 @@ class AbsenceController extends AbstractController
|
|||||||
$user = $this->security->getUser();
|
$user = $this->security->getUser();
|
||||||
|
|
||||||
$user->setAbsenceStart(null);
|
$user->setAbsenceStart(null);
|
||||||
|
$user->setAbsenceEnd(null);
|
||||||
$em = $this->managerRegistry->getManager();
|
$em = $this->managerRegistry->getManager();
|
||||||
$em->flush();
|
$em->flush();
|
||||||
|
|
||||||
|
@@ -1,63 +0,0 @@
|
|||||||
<?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\MainBundle\Controller;
|
|
||||||
|
|
||||||
use Chill\MainBundle\Form\UserProfileType;
|
|
||||||
use Chill\MainBundle\Security\ChillSecurity;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
|
||||||
|
|
||||||
final class UserProfileController extends AbstractController
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private readonly TranslatorInterface $translator,
|
|
||||||
private readonly ChillSecurity $security,
|
|
||||||
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User profile that allows editing of phonenumber and visualization of certain data.
|
|
||||||
*/
|
|
||||||
#[Route(path: '/{_locale}/main/user/my-profile', name: 'chill_main_user_profile')]
|
|
||||||
public function __invoke(Request $request)
|
|
||||||
{
|
|
||||||
if (!$this->security->isGranted('ROLE_USER')) {
|
|
||||||
throw new AccessDeniedHttpException();
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = $this->security->getUser();
|
|
||||||
$editForm = $this->createForm(UserProfileType::class, $user);
|
|
||||||
|
|
||||||
$editForm->get('notificationFlags')->setData($user->getNotificationFlags());
|
|
||||||
|
|
||||||
$editForm->handleRequest($request);
|
|
||||||
|
|
||||||
if ($editForm->isSubmitted() && $editForm->isValid()) {
|
|
||||||
$notificationFlagsData = $editForm->get('notificationFlags')->getData();
|
|
||||||
$user->setNotificationFlags($notificationFlagsData);
|
|
||||||
|
|
||||||
$em = $this->managerRegistry->getManager();
|
|
||||||
$em->flush();
|
|
||||||
$this->addFlash('success', $this->translator->trans('user.profile.Profile successfully updated!'));
|
|
||||||
|
|
||||||
return $this->redirectToRoute('chill_main_user_profile');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->render('@ChillMain/User/profile.html.twig', [
|
|
||||||
'user' => $user,
|
|
||||||
'form' => $editForm->createView(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,75 @@
|
|||||||
|
<?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\MainBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Action\User\UpdateProfile\UpdateProfileCommand;
|
||||||
|
use Chill\MainBundle\Action\User\UpdateProfile\UpdateProfileCommandHandler;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Form\UpdateProfileType;
|
||||||
|
use Chill\MainBundle\Notification\NotificationFlagManager;
|
||||||
|
use Chill\MainBundle\Security\ChillSecurity;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Component\Form\FormFactoryInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Session;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||||
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Twig\Environment;
|
||||||
|
|
||||||
|
final readonly class UserUpdateProfileController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private TranslatorInterface $translator,
|
||||||
|
private ChillSecurity $security,
|
||||||
|
private EntityManagerInterface $entityManager,
|
||||||
|
private NotificationFlagManager $notificationFlagManager,
|
||||||
|
private FormFactoryInterface $formFactory,
|
||||||
|
private UrlGeneratorInterface $urlGenerator,
|
||||||
|
private Environment $twig,
|
||||||
|
private UpdateProfileCommandHandler $updateProfileCommandHandler,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User profile that allows editing of phonenumber and visualization of certain data.
|
||||||
|
*/
|
||||||
|
#[Route(path: '/{_locale}/main/user/my-profile', name: 'chill_main_user_profile')]
|
||||||
|
public function __invoke(Request $request, Session $session)
|
||||||
|
{
|
||||||
|
if (!$this->security->isGranted('ROLE_USER')) {
|
||||||
|
throw new AccessDeniedHttpException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
|
||||||
|
$command = UpdateProfileCommand::create($user, $this->notificationFlagManager);
|
||||||
|
$editForm = $this->formFactory->create(UpdateProfileType::class, $command);
|
||||||
|
|
||||||
|
$editForm->handleRequest($request);
|
||||||
|
|
||||||
|
if ($editForm->isSubmitted() && $editForm->isValid()) {
|
||||||
|
$this->updateProfileCommandHandler->updateProfile($user, $command);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
$session->getFlashBag()->add('success', $this->translator->trans('user.profile.Profile successfully updated!'));
|
||||||
|
|
||||||
|
return new RedirectResponse($this->urlGenerator->generate('chill_main_user_profile'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response($this->twig->render('@ChillMain/User/profile.html.twig', [
|
||||||
|
'user' => $user,
|
||||||
|
'form' => $editForm->createView(),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
@@ -24,6 +24,7 @@ use Symfony\Component\Security\Core\User\UserInterface;
|
|||||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||||
use Chill\MainBundle\Validation\Constraint\PhonenumberConstraint;
|
use Chill\MainBundle\Validation\Constraint\PhonenumberConstraint;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User.
|
* User.
|
||||||
@@ -45,6 +46,8 @@ class User implements UserInterface, \Stringable, PasswordAuthenticatedUserInter
|
|||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE, nullable: true)]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE, nullable: true)]
|
||||||
private ?\DateTimeImmutable $absenceStart = null;
|
private ?\DateTimeImmutable $absenceStart = null;
|
||||||
|
|
||||||
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE, nullable: true)]
|
||||||
|
private ?\DateTimeImmutable $absenceEnd = null;
|
||||||
/**
|
/**
|
||||||
* Array where SAML attributes's data are stored.
|
* Array where SAML attributes's data are stored.
|
||||||
*/
|
*/
|
||||||
@@ -157,6 +160,11 @@ class User implements UserInterface, \Stringable, PasswordAuthenticatedUserInter
|
|||||||
return $this->absenceStart;
|
return $this->absenceStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAbsenceEnd(): ?\DateTimeImmutable
|
||||||
|
{
|
||||||
|
return $this->absenceEnd;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get attributes.
|
* Get attributes.
|
||||||
*
|
*
|
||||||
@@ -336,7 +344,13 @@ class User implements UserInterface, \Stringable, PasswordAuthenticatedUserInter
|
|||||||
|
|
||||||
public function isAbsent(): bool
|
public function isAbsent(): bool
|
||||||
{
|
{
|
||||||
return null !== $this->getAbsenceStart() && $this->getAbsenceStart() <= new \DateTimeImmutable('now');
|
$now = new \DateTimeImmutable('now');
|
||||||
|
$absenceStart = $this->getAbsenceStart();
|
||||||
|
$absenceEnd = $this->getAbsenceEnd();
|
||||||
|
|
||||||
|
return null !== $absenceStart
|
||||||
|
&& $absenceStart <= $now
|
||||||
|
&& (null === $absenceEnd || $now <= $absenceEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -410,6 +424,11 @@ class User implements UserInterface, \Stringable, PasswordAuthenticatedUserInter
|
|||||||
$this->absenceStart = $absenceStart;
|
$this->absenceStart = $absenceStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setAbsenceEnd(?\DateTimeImmutable $absenceEnd): void
|
||||||
|
{
|
||||||
|
$this->absenceEnd = $absenceEnd;
|
||||||
|
}
|
||||||
|
|
||||||
public function setAttributeByDomain(string $domain, string $key, $value): self
|
public function setAttributeByDomain(string $domain, string $key, $value): self
|
||||||
{
|
{
|
||||||
$this->attributes[$domain][$key] = $value;
|
$this->attributes[$domain][$key] = $value;
|
||||||
@@ -633,46 +652,82 @@ class User implements UserInterface, \Stringable, PasswordAuthenticatedUserInter
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getNotificationFlags(): array
|
private function getNotificationFlagData(string $flag): array
|
||||||
{
|
{
|
||||||
return $this->notificationFlags;
|
return $this->notificationFlags[$flag] ?? [self::NOTIF_FLAG_IMMEDIATE_EMAIL];
|
||||||
}
|
|
||||||
|
|
||||||
public function setNotificationFlags(array $notificationFlags)
|
|
||||||
{
|
|
||||||
$this->notificationFlags = $notificationFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNotificationFlagData(string $flag): array
|
|
||||||
{
|
|
||||||
return $this->notificationFlags[$flag] ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setNotificationFlagData(string $flag, array $data): void
|
|
||||||
{
|
|
||||||
$this->notificationFlags[$flag] = $data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isNotificationSendImmediately(string $type): bool
|
public function isNotificationSendImmediately(string $type): bool
|
||||||
{
|
{
|
||||||
if ([] === $this->getNotificationFlagData($type) || in_array(User::NOTIF_FLAG_IMMEDIATE_EMAIL, $this->getNotificationFlagData($type), true)) {
|
return $this->isNotificationForElement($type, self::NOTIF_FLAG_IMMEDIATE_EMAIL);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
public function setNotificationImmediately(string $type, bool $active): void
|
||||||
|
{
|
||||||
|
$this->setNotificationFlagElement($type, $active, self::NOTIF_FLAG_IMMEDIATE_EMAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNotificationDailyDigest(string $type, bool $active): void
|
||||||
|
{
|
||||||
|
$this->setNotificationFlagElement($type, $active, self::NOTIF_FLAG_DAILY_DIGEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param self::NOTIF_FLAG_IMMEDIATE_EMAIL|self::NOTIF_FLAG_DAILY_DIGEST $kind
|
||||||
|
*/
|
||||||
|
private function setNotificationFlagElement(string $type, bool $active, string $kind): void
|
||||||
|
{
|
||||||
|
$notificationFlags = [...$this->notificationFlags];
|
||||||
|
$changed = false;
|
||||||
|
|
||||||
|
if (!isset($notificationFlags[$type])) {
|
||||||
|
$notificationFlags[$type] = [self::NOTIF_FLAG_IMMEDIATE_EMAIL];
|
||||||
|
$changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($active) {
|
||||||
|
if (!in_array($kind, $notificationFlags[$type], true)) {
|
||||||
|
$notificationFlags[$type] = [...$notificationFlags[$type], $kind];
|
||||||
|
$changed = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (in_array($kind, $notificationFlags[$type], true)) {
|
||||||
|
$notificationFlags[$type] = array_values(
|
||||||
|
array_filter($notificationFlags[$type], static fn ($k) => $k !== $kind)
|
||||||
|
);
|
||||||
|
$changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($changed) {
|
||||||
|
$this->notificationFlags = [...$notificationFlags];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isNotificationForElement(string $type, string $kind): bool
|
||||||
|
{
|
||||||
|
return in_array($kind, $this->getNotificationFlagData($type), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isNotificationDailyDigest(string $type): bool
|
public function isNotificationDailyDigest(string $type): bool
|
||||||
{
|
{
|
||||||
if (in_array(User::NOTIF_FLAG_DAILY_DIGEST, $this->getNotificationFlagData($type), true)) {
|
return $this->isNotificationForElement($type, self::NOTIF_FLAG_DAILY_DIGEST);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLocale(): string
|
public function getLocale(): string
|
||||||
{
|
{
|
||||||
return 'fr';
|
return 'fr';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Assert\Callback]
|
||||||
|
public function validateAbsenceDates(ExecutionContextInterface $context): void
|
||||||
|
{
|
||||||
|
if (null !== $this->getAbsenceEnd() && null === $this->getAbsenceStart()) {
|
||||||
|
$context->buildViolation(
|
||||||
|
'user.absence_end_requires_start'
|
||||||
|
)
|
||||||
|
->atPath('absenceEnd')
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,8 +27,6 @@ use Symfony\Component\HttpFoundation\Response;
|
|||||||
use Symfony\Contracts\Translation\TranslatableInterface;
|
use Symfony\Contracts\Translation\TranslatableInterface;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
// command to get the report with curl : curl --user "center a_social:password" "http://localhost:8000/fr/exports/generate/count_person?export[filters][person_gender_filter][enabled]=&export[filters][person_nationality_filter][enabled]=&export[filters][person_nationality_filter][form][nationalities]=&export[aggregators][person_nationality_aggregator][order]=1&export[aggregators][person_nationality_aggregator][form][group_by_level]=country&export[submit]=&export[_token]=RHpjHl389GrK-bd6iY5NsEqrD5UKOTHH40QKE9J1edU" --globoff
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a CSV List for the export.
|
* Create a CSV List for the export.
|
||||||
*/
|
*/
|
||||||
|
@@ -23,9 +23,14 @@ class AbsenceType extends AbstractType
|
|||||||
{
|
{
|
||||||
$builder
|
$builder
|
||||||
->add('absenceStart', ChillDateType::class, [
|
->add('absenceStart', ChillDateType::class, [
|
||||||
'required' => true,
|
'required' => false,
|
||||||
'input' => 'datetime_immutable',
|
'input' => 'datetime_immutable',
|
||||||
'label' => 'absence.Absence start',
|
'label' => 'absence.Absence start',
|
||||||
|
])
|
||||||
|
->add('absenceEnd', ChillDateType::class, [
|
||||||
|
'required' => false,
|
||||||
|
'input' => 'datetime_immutable',
|
||||||
|
'label' => 'absence.Absence end',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,75 +0,0 @@
|
|||||||
<?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\MainBundle\Form\DataMapper;
|
|
||||||
|
|
||||||
use Chill\MainBundle\Entity\User;
|
|
||||||
use Symfony\Component\Form\DataMapperInterface;
|
|
||||||
|
|
||||||
final readonly class NotificationFlagDataMapper implements DataMapperInterface
|
|
||||||
{
|
|
||||||
public function __construct(private array $notificationFlagProviders) {}
|
|
||||||
|
|
||||||
public function mapDataToForms($viewData, $forms): void
|
|
||||||
{
|
|
||||||
if (null === $viewData) {
|
|
||||||
$viewData = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$formsArray = iterator_to_array($forms);
|
|
||||||
|
|
||||||
foreach ($this->notificationFlagProviders as $flagProvider) {
|
|
||||||
$flag = $flagProvider->getFlag();
|
|
||||||
|
|
||||||
if (isset($formsArray[$flag])) {
|
|
||||||
$flagForm = $formsArray[$flag];
|
|
||||||
|
|
||||||
$immediateEmailChecked = in_array(User::NOTIF_FLAG_IMMEDIATE_EMAIL, $viewData[$flag] ?? [], true)
|
|
||||||
|| !array_key_exists($flag, $viewData);
|
|
||||||
$dailyEmailChecked = in_array(User::NOTIF_FLAG_DAILY_DIGEST, $viewData[$flag] ?? [], true);
|
|
||||||
|
|
||||||
if ($flagForm->has('immediate_email')) {
|
|
||||||
$flagForm->get('immediate_email')->setData($immediateEmailChecked);
|
|
||||||
}
|
|
||||||
if ($flagForm->has('daily_email')) {
|
|
||||||
$flagForm->get('daily_email')->setData($dailyEmailChecked);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function mapFormsToData($forms, &$viewData): void
|
|
||||||
{
|
|
||||||
$formsArray = iterator_to_array($forms);
|
|
||||||
$viewData = [];
|
|
||||||
|
|
||||||
foreach ($this->notificationFlagProviders as $flagProvider) {
|
|
||||||
$flag = $flagProvider->getFlag();
|
|
||||||
|
|
||||||
if (isset($formsArray[$flag])) {
|
|
||||||
$flagForm = $formsArray[$flag];
|
|
||||||
$viewData[$flag] = [];
|
|
||||||
|
|
||||||
if (true === $flagForm['immediate_email']->getData()) {
|
|
||||||
$viewData[$flag][] = User::NOTIF_FLAG_IMMEDIATE_EMAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (true === $flagForm['daily_email']->getData()) {
|
|
||||||
$viewData[$flag][] = User::NOTIF_FLAG_DAILY_DIGEST;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([] === $viewData[$flag]) {
|
|
||||||
$viewData[$flag][] = User::NOTIF_FLAG_IMMEDIATE_EMAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -11,11 +11,9 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\MainBundle\Form\Type;
|
namespace Chill\MainBundle\Form\Type;
|
||||||
|
|
||||||
use Chill\MainBundle\Form\DataMapper\NotificationFlagDataMapper;
|
|
||||||
use Chill\MainBundle\Notification\NotificationFlagManager;
|
use Chill\MainBundle\Notification\NotificationFlagManager;
|
||||||
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\FormType;
|
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
@@ -30,27 +28,24 @@ class NotificationFlagsType extends AbstractType
|
|||||||
|
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
{
|
{
|
||||||
$builder->setDataMapper(new NotificationFlagDataMapper($this->notificationFlagProviders));
|
|
||||||
|
|
||||||
foreach ($this->notificationFlagProviders as $flagProvider) {
|
foreach ($this->notificationFlagProviders as $flagProvider) {
|
||||||
$flag = $flagProvider->getFlag();
|
$flag = $flagProvider->getFlag();
|
||||||
$builder->add($flag, FormType::class, [
|
$flagBuilder = $builder->create($flag, options: [
|
||||||
'label' => $flagProvider->getLabel(),
|
'label' => $flagProvider->getLabel(),
|
||||||
'required' => false,
|
'compound' => true,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$builder->get($flag)
|
$flagBuilder
|
||||||
->add('immediate_email', CheckboxType::class, [
|
->add('immediate_email', CheckboxType::class, [
|
||||||
'label' => false,
|
'label' => false,
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'mapped' => false,
|
|
||||||
])
|
])
|
||||||
->add('daily_email', CheckboxType::class, [
|
->add('daily_digest', CheckboxType::class, [
|
||||||
'label' => false,
|
'label' => false,
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'mapped' => false,
|
|
||||||
])
|
])
|
||||||
;
|
;
|
||||||
|
$builder->add($flagBuilder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +53,7 @@ class NotificationFlagsType extends AbstractType
|
|||||||
{
|
{
|
||||||
$resolver->setDefaults([
|
$resolver->setDefaults([
|
||||||
'data_class' => null,
|
'data_class' => null,
|
||||||
|
'compound' => true,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,31 +11,29 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\MainBundle\Form;
|
namespace Chill\MainBundle\Form;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Action\User\UpdateProfile\UpdateProfileCommand;
|
||||||
use Chill\MainBundle\Form\Type\ChillPhoneNumberType;
|
use Chill\MainBundle\Form\Type\ChillPhoneNumberType;
|
||||||
use Chill\MainBundle\Form\Type\NotificationFlagsType;
|
use Chill\MainBundle\Form\Type\NotificationFlagsType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
class UserProfileType extends AbstractType
|
class UpdateProfileType extends AbstractType
|
||||||
{
|
{
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
{
|
{
|
||||||
$builder
|
$builder
|
||||||
->add('phonenumber', ChillPhoneNumberType::class, [
|
->add('phonenumber', ChillPhoneNumberType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
])
|
])
|
||||||
->add('notificationFlags', NotificationFlagsType::class, [
|
->add('notificationFlags', NotificationFlagsType::class)
|
||||||
'label' => false,
|
|
||||||
'mapped' => false,
|
|
||||||
])
|
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver)
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
{
|
{
|
||||||
$resolver->setDefaults([
|
$resolver->setDefaults([
|
||||||
'data_class' => \Chill\MainBundle\Entity\User::class,
|
'data_class' => UpdateProfileCommand::class,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -105,6 +105,11 @@ class UserType extends AbstractType
|
|||||||
'required' => false,
|
'required' => false,
|
||||||
'input' => 'datetime_immutable',
|
'input' => 'datetime_immutable',
|
||||||
'label' => 'absence.Absence start',
|
'label' => 'absence.Absence start',
|
||||||
|
])
|
||||||
|
->add('absenceEnd', ChillDateType::class, [
|
||||||
|
'required' => false,
|
||||||
|
'input' => 'datetime_immutable',
|
||||||
|
'label' => 'absence.Absence end',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// @phpstan-ignore-next-line
|
// @phpstan-ignore-next-line
|
||||||
|
@@ -76,24 +76,6 @@ final class PhonenumberHelper implements PhoneNumberHelperInterface
|
|||||||
->formatOutOfCountryCallingNumber($phoneNumber, $this->config['default_carrier_code']);
|
->formatOutOfCountryCallingNumber($phoneNumber, $this->config['default_carrier_code']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws NumberParseException
|
|
||||||
*/
|
|
||||||
public function parse(string $phoneNumber): PhoneNumber
|
|
||||||
{
|
|
||||||
$sanitizedPhoneNumber = $phoneNumber;
|
|
||||||
|
|
||||||
if (str_starts_with($sanitizedPhoneNumber, '00')) {
|
|
||||||
$sanitizedPhoneNumber = '+'.substr($sanitizedPhoneNumber, 2, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!str_starts_with($sanitizedPhoneNumber, '+') && !str_starts_with($sanitizedPhoneNumber, '0')) {
|
|
||||||
$sanitizedPhoneNumber = '+'.$sanitizedPhoneNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->phoneNumberUtil->parse($sanitizedPhoneNumber, $this->config['default_carrier_code']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get type (mobile, landline, ...) for phone number.
|
* Get type (mobile, landline, ...) for phone number.
|
||||||
*/
|
*/
|
||||||
|
@@ -37,8 +37,13 @@ export const ISOToDate = (str: string | null): Date | null => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [year, month, day] = str.split("-").map((p) => parseInt(p));
|
// If the string already contains time info, use it directly
|
||||||
|
if (str.includes("T") || str.includes(" ")) {
|
||||||
|
return new Date(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, parse date only
|
||||||
|
const [year, month, day] = str.split("-").map((p) => parseInt(p));
|
||||||
return new Date(year, month - 1, day, 0, 0, 0, 0);
|
return new Date(year, month - 1, day, 0, 0, 0, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -56,7 +61,9 @@ export const ISOToDatetime = (str: string | null): Date | null => {
|
|||||||
[time, timezone] = times.split(times.charAt(8)),
|
[time, timezone] = times.split(times.charAt(8)),
|
||||||
[hours, minutes, seconds] = time.split(":").map((s) => parseInt(s));
|
[hours, minutes, seconds] = time.split(":").map((s) => parseInt(s));
|
||||||
if ("0000" === timezone) {
|
if ("0000" === timezone) {
|
||||||
return new Date(Date.UTC(year, month - 1, date, hours, minutes, seconds));
|
return new Date(
|
||||||
|
Date.UTC(year, month - 1, date, hours, minutes, seconds),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Date(year, month - 1, date, hours, minutes, seconds);
|
return new Date(year, month - 1, date, hours, minutes, seconds);
|
||||||
@@ -67,20 +74,19 @@ export const ISOToDatetime = (str: string | null): Date | null => {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const datetimeToISO = (date: Date): string => {
|
export const datetimeToISO = (date: Date): string => {
|
||||||
let cal, time, offset;
|
const cal = [
|
||||||
cal = [
|
|
||||||
date.getFullYear(),
|
date.getFullYear(),
|
||||||
(date.getMonth() + 1).toString().padStart(2, "0"),
|
(date.getMonth() + 1).toString().padStart(2, "0"),
|
||||||
date.getDate().toString().padStart(2, "0"),
|
date.getDate().toString().padStart(2, "0"),
|
||||||
].join("-");
|
].join("-");
|
||||||
|
|
||||||
time = [
|
const time = [
|
||||||
date.getHours().toString().padStart(2, "0"),
|
date.getHours().toString().padStart(2, "0"),
|
||||||
date.getMinutes().toString().padStart(2, "0"),
|
date.getMinutes().toString().padStart(2, "0"),
|
||||||
date.getSeconds().toString().padStart(2, "0"),
|
date.getSeconds().toString().padStart(2, "0"),
|
||||||
].join(":");
|
].join(":");
|
||||||
|
|
||||||
offset = [
|
const offset = [
|
||||||
date.getTimezoneOffset() <= 0 ? "+" : "-",
|
date.getTimezoneOffset() <= 0 ? "+" : "-",
|
||||||
Math.abs(Math.floor(date.getTimezoneOffset() / 60))
|
Math.abs(Math.floor(date.getTimezoneOffset() / 60))
|
||||||
.toString()
|
.toString()
|
||||||
@@ -152,7 +158,9 @@ export const intervalISOToDays = (str: string | null): number | null => {
|
|||||||
vstring = "";
|
vstring = "";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw Error("this character should not appears: " + str.charAt(i));
|
throw Error(
|
||||||
|
"this character should not appears: " + str.charAt(i),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,16 +5,11 @@ export type fetchOption = Record<string, boolean | string | number | null>;
|
|||||||
|
|
||||||
export type Params = Record<string, number | string>;
|
export type Params = Record<string, number | string>;
|
||||||
|
|
||||||
export interface Pagination {
|
|
||||||
first: number;
|
|
||||||
items_per_page: number;
|
|
||||||
more: boolean;
|
|
||||||
next: string | null;
|
|
||||||
previous: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PaginationResponse<T> {
|
export interface PaginationResponse<T> {
|
||||||
pagination: Pagination;
|
pagination: {
|
||||||
|
more: boolean;
|
||||||
|
items_per_page: number;
|
||||||
|
};
|
||||||
results: T[];
|
results: T[];
|
||||||
count: number;
|
count: number;
|
||||||
}
|
}
|
||||||
|
@@ -8,26 +8,6 @@ import { TranslatableString } from "ChillMainAssets/types";
|
|||||||
* @param locale defaults to browser locale
|
* @param locale defaults to browser locale
|
||||||
* @returns The localized string or null if no translation is available
|
* @returns The localized string or null if no translation is available
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepends the current HTML lang code to the given URL.
|
|
||||||
* Example: If lang="fr" and url="/about", returns "/fr/about"
|
|
||||||
*
|
|
||||||
* @param url The URL to localize
|
|
||||||
* @returns The localized URL
|
|
||||||
*/
|
|
||||||
export function localizedUrl(url: string): string {
|
|
||||||
const lang =
|
|
||||||
document.documentElement.lang || navigator.language.split("-")[0] || "fr";
|
|
||||||
// Ensure url starts with a slash and does not already start with /{lang}/
|
|
||||||
const normalizedUrl = url.startsWith("/") ? url : `/${url}`;
|
|
||||||
const langPrefix = `/${lang}`;
|
|
||||||
if (normalizedUrl.startsWith(langPrefix + "/")) {
|
|
||||||
return normalizedUrl;
|
|
||||||
}
|
|
||||||
return `${langPrefix}${normalizedUrl}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function localizeString(
|
export function localizeString(
|
||||||
translatableString: TranslatableString | null | undefined,
|
translatableString: TranslatableString | null | undefined,
|
||||||
locale?: string,
|
locale?: string,
|
||||||
|
@@ -126,8 +126,7 @@ function loadDynamicPicker(element) {
|
|||||||
-1 ===
|
-1 ===
|
||||||
this.suggested.findIndex(
|
this.suggested.findIndex(
|
||||||
(e) => e.type === entity.type && e.id === entity.id,
|
(e) => e.type === entity.type && e.id === entity.id,
|
||||||
) &&
|
)
|
||||||
"me" !== entity
|
|
||||||
) {
|
) {
|
||||||
this.suggested.push(entity);
|
this.suggested.push(entity);
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,15 @@
|
|||||||
|
import { createApp } from "vue";
|
||||||
|
import { _createI18n } from "ChillMainAssets/vuejs/_js/i18n";
|
||||||
|
import { appMessages } from "ChillMainAssets/vuejs/HomepageWidget/js/i18n";
|
||||||
|
import { store } from "ChillMainAssets/vuejs/HomepageWidget/js/store";
|
||||||
|
import App from "ChillMainAssets/vuejs/HomepageWidget/App";
|
||||||
|
|
||||||
|
const i18n = _createI18n(appMessages);
|
||||||
|
|
||||||
|
const app = createApp({
|
||||||
|
template: `<app></app>`,
|
||||||
|
})
|
||||||
|
.use(store)
|
||||||
|
.use(i18n)
|
||||||
|
.component("app", App)
|
||||||
|
.mount("#homepage_widget");
|
@@ -1,12 +0,0 @@
|
|||||||
import App from "ChillMainAssets/vuejs/HomepageWidget/App.vue";
|
|
||||||
import { createApp } from "vue";
|
|
||||||
import { store } from "ChillMainAssets/vuejs/HomepageWidget/store";
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
homepage_config: string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const _app = createApp(App);
|
|
||||||
_app.use(store).mount("#homepage_widget");
|
|
@@ -11,11 +11,6 @@ export interface Civility {
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Household {
|
|
||||||
type: "household";
|
|
||||||
id: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Job {
|
export interface Job {
|
||||||
id: number;
|
id: number;
|
||||||
type: "user_job";
|
type: "user_job";
|
||||||
@@ -220,83 +215,3 @@ export interface ExportGeneration {
|
|||||||
export interface PrivateCommentEmbeddable {
|
export interface PrivateCommentEmbeddable {
|
||||||
comments: Record<number, string>;
|
comments: Record<number, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// API Exception types
|
|
||||||
export interface TransportExceptionInterface {
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ValidationExceptionInterface
|
|
||||||
extends TransportExceptionInterface {
|
|
||||||
name: "ValidationException";
|
|
||||||
error: object;
|
|
||||||
violations: string[];
|
|
||||||
titles: string[];
|
|
||||||
propertyPaths: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AccessExceptionInterface extends TransportExceptionInterface {
|
|
||||||
name: "AccessException";
|
|
||||||
violations: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NotFoundExceptionInterface
|
|
||||||
extends TransportExceptionInterface {
|
|
||||||
name: "NotFoundException";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ServerExceptionInterface extends TransportExceptionInterface {
|
|
||||||
name: "ServerException";
|
|
||||||
message: string;
|
|
||||||
code: number;
|
|
||||||
body: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ConflictHttpExceptionInterface
|
|
||||||
extends TransportExceptionInterface {
|
|
||||||
name: "ConflictHttpException";
|
|
||||||
violations: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ApiException =
|
|
||||||
| ValidationExceptionInterface
|
|
||||||
| AccessExceptionInterface
|
|
||||||
| NotFoundExceptionInterface
|
|
||||||
| ServerExceptionInterface
|
|
||||||
| ConflictHttpExceptionInterface;
|
|
||||||
|
|
||||||
export interface Modal {
|
|
||||||
showModal: boolean;
|
|
||||||
modalDialogClass: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Selected {
|
|
||||||
result: UserGroupOrUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface addNewEntities {
|
|
||||||
selected: Selected[];
|
|
||||||
modal: Modal;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum HomepageTabs {
|
|
||||||
MyCustoms,
|
|
||||||
MyTickets,
|
|
||||||
MyNotifications,
|
|
||||||
MyAccompanyingCourses,
|
|
||||||
MyEvaluations,
|
|
||||||
MyTasks,
|
|
||||||
MyWorkflows,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HomepageConfig {
|
|
||||||
defaultTab: HomepageTabs;
|
|
||||||
displayTabs: HomepageTabs[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabDefinition {
|
|
||||||
key: HomepageTabs;
|
|
||||||
label: string;
|
|
||||||
icon: string | null;
|
|
||||||
counter: () => number;
|
|
||||||
}
|
|
||||||
|
@@ -148,7 +148,10 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #action>
|
<template #action>
|
||||||
<li v-if="!this.context.edit && this.useDatePane">
|
<li v-if="!this.context.edit && this.useDatePane">
|
||||||
<button class="btn btn-update change-icon" @click="closeEditPane">
|
<button
|
||||||
|
class="btn btn-update change-icon"
|
||||||
|
@click="closeEditPane"
|
||||||
|
>
|
||||||
{{ trans(NEXT) }}
|
{{ trans(NEXT) }}
|
||||||
<i class="fa fa-fw fa-arrow-right" />
|
<i class="fa fa-fw fa-arrow-right" />
|
||||||
</button>
|
</button>
|
||||||
@@ -274,7 +277,8 @@ export default {
|
|||||||
PREVIOUS,
|
PREVIOUS,
|
||||||
NEXT,
|
NEXT,
|
||||||
};
|
};
|
||||||
},props: ["context", "options", "addressChangedCallback"],
|
},
|
||||||
|
props: ["context", "options", "addressChangedCallback"],
|
||||||
components: {
|
components: {
|
||||||
Modal,
|
Modal,
|
||||||
ShowPane,
|
ShowPane,
|
||||||
@@ -390,7 +394,8 @@ export default {
|
|||||||
getTextTitle() {
|
getTextTitle() {
|
||||||
if (
|
if (
|
||||||
typeof this.options.title !== "undefined" &&
|
typeof this.options.title !== "undefined" &&
|
||||||
(this.options.title.edit !== null || this.options.title.create !== null)
|
(this.options.title.edit !== null ||
|
||||||
|
this.options.title.create !== null)
|
||||||
) {
|
) {
|
||||||
console.log("this.options.title", this.options.title);
|
console.log("this.options.title", this.options.title);
|
||||||
|
|
||||||
@@ -510,7 +515,10 @@ export default {
|
|||||||
if (!this.context.edit) {
|
if (!this.context.edit) {
|
||||||
this.context.edit = true;
|
this.context.edit = true;
|
||||||
this.context.addressId = params.addressId;
|
this.context.addressId = params.addressId;
|
||||||
console.log("context is now edit, with address", params.addressId);
|
console.log(
|
||||||
|
"context is now edit, with address",
|
||||||
|
params.addressId,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -637,7 +645,9 @@ export default {
|
|||||||
? this.entity.address.confidential
|
? this.entity.address.confidential
|
||||||
: false;
|
: false;
|
||||||
this.entity.selected.isNoAddress =
|
this.entity.selected.isNoAddress =
|
||||||
this.context.edit && this.entity.address.text === "" ? true : false;
|
this.context.edit && this.entity.address.text === ""
|
||||||
|
? true
|
||||||
|
: false;
|
||||||
|
|
||||||
this.entity.selected.country = this.context.edit
|
this.entity.selected.country = this.context.edit
|
||||||
? this.entity.address.country
|
? this.entity.address.country
|
||||||
@@ -732,7 +742,8 @@ export default {
|
|||||||
// add the address reference, if any
|
// add the address reference, if any
|
||||||
if (this.entity.selected.address.addressReference !== undefined) {
|
if (this.entity.selected.address.addressReference !== undefined) {
|
||||||
newAddress = Object.assign(newAddress, {
|
newAddress = Object.assign(newAddress, {
|
||||||
addressReference: this.entity.selected.address.addressReference,
|
addressReference:
|
||||||
|
this.entity.selected.address.addressReference,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
newAddress = Object.assign(newAddress, {
|
newAddress = Object.assign(newAddress, {
|
||||||
@@ -752,7 +763,10 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (this.validTo && null !== this.entity.selected.valid.to) {
|
if (this.validTo && null !== this.entity.selected.valid.to) {
|
||||||
console.log("add validTo in fetch body", this.entity.selected.valid.to);
|
console.log(
|
||||||
|
"add validTo in fetch body",
|
||||||
|
this.entity.selected.valid.to,
|
||||||
|
);
|
||||||
newAddress = Object.assign(newAddress, {
|
newAddress = Object.assign(newAddress, {
|
||||||
validTo: {
|
validTo: {
|
||||||
datetime: `${this.entity.selected.valid.to.toISOString().split("T")[0]}T00:00:00+0100`,
|
datetime: `${this.entity.selected.valid.to.toISOString().split("T")[0]}T00:00:00+0100`,
|
||||||
@@ -764,7 +778,10 @@ export default {
|
|||||||
newPostcode = Object.assign(newPostcode, {
|
newPostcode = Object.assign(newPostcode, {
|
||||||
country: { id: this.entity.selected.country.id },
|
country: { id: this.entity.selected.country.id },
|
||||||
}); //TODO why not assign postcodeBody here = Object.assign(postcodeBody, {'origin': 3}); ?
|
}); //TODO why not assign postcodeBody here = Object.assign(postcodeBody, {'origin': 3}); ?
|
||||||
console.log("writeNew postcode is true! newPostcode: ", newPostcode);
|
console.log(
|
||||||
|
"writeNew postcode is true! newPostcode: ",
|
||||||
|
newPostcode,
|
||||||
|
);
|
||||||
newAddress = Object.assign(newAddress, {
|
newAddress = Object.assign(newAddress, {
|
||||||
newPostcode: newPostcode,
|
newPostcode: newPostcode,
|
||||||
});
|
});
|
||||||
|
@@ -72,7 +72,10 @@ export default {
|
|||||||
this.entity.addressMap.zoom,
|
this.entity.addressMap.zoom,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.map.setView(lonLatForLeaflet(this.addressPoint.coordinates), 15);
|
this.map.setView(
|
||||||
|
lonLatForLeaflet(this.addressPoint.coordinates),
|
||||||
|
15,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.map.scrollWheelZoom.disable();
|
this.map.scrollWheelZoom.disable();
|
||||||
@@ -102,7 +105,9 @@ export default {
|
|||||||
},
|
},
|
||||||
update() {
|
update() {
|
||||||
if (this.marker && this.entity.addressMap.center) {
|
if (this.marker && this.entity.addressMap.center) {
|
||||||
this.marker.setLatLng(lonLatForLeaflet(this.entity.addressMap.center));
|
this.marker.setLatLng(
|
||||||
|
lonLatForLeaflet(this.entity.addressMap.center),
|
||||||
|
);
|
||||||
this.map.panTo(lonLatForLeaflet(this.entity.addressMap.center));
|
this.map.panTo(lonLatForLeaflet(this.entity.addressMap.center));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@@ -117,7 +117,8 @@ export default {
|
|||||||
ADDRESS_FILL_AN_ADDRESS,
|
ADDRESS_FILL_AN_ADDRESS,
|
||||||
trans,
|
trans,
|
||||||
};
|
};
|
||||||
},props: ["entity", "isNoAddress"],
|
},
|
||||||
|
props: ["entity", "isNoAddress"],
|
||||||
computed: {
|
computed: {
|
||||||
floor: {
|
floor: {
|
||||||
set(value) {
|
set(value) {
|
||||||
|
@@ -96,10 +96,13 @@ export default {
|
|||||||
ADDRESS_CREATE_ADDRESS,
|
ADDRESS_CREATE_ADDRESS,
|
||||||
trans,
|
trans,
|
||||||
};
|
};
|
||||||
},props: ["entity", "context", "updateMapCenter", "flag", "checkErrors"],
|
},
|
||||||
|
props: ["entity", "context", "updateMapCenter", "flag", "checkErrors"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
value: this.context.edit ? this.entity.address.addressReference : null,
|
value: this.context.edit
|
||||||
|
? this.entity.address.addressReference
|
||||||
|
: null,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -172,7 +175,8 @@ export default {
|
|||||||
.then(
|
.then(
|
||||||
(addresses) =>
|
(addresses) =>
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
this.entity.loaded.addresses = addresses.results;
|
this.entity.loaded.addresses =
|
||||||
|
addresses.results;
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
resolve();
|
resolve();
|
||||||
}),
|
}),
|
||||||
@@ -189,7 +193,8 @@ export default {
|
|||||||
.then(
|
.then(
|
||||||
(addresses) =>
|
(addresses) =>
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
this.entity.loaded.addresses = addresses.results;
|
this.entity.loaded.addresses =
|
||||||
|
addresses.results;
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
resolve();
|
resolve();
|
||||||
}),
|
}),
|
||||||
|
@@ -85,7 +85,8 @@ export default {
|
|||||||
ADDRESS_CREATE_POSTAL_CODE,
|
ADDRESS_CREATE_POSTAL_CODE,
|
||||||
trans,
|
trans,
|
||||||
};
|
};
|
||||||
},props: [
|
},
|
||||||
|
props: [
|
||||||
"entity",
|
"entity",
|
||||||
"context",
|
"context",
|
||||||
"focusOnAddress",
|
"focusOnAddress",
|
||||||
@@ -157,7 +158,9 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
transName(value) {
|
transName(value) {
|
||||||
return value.code && value.name ? `${value.name} (${value.code})` : "";
|
return value.code && value.name
|
||||||
|
? `${value.name} (${value.code})`
|
||||||
|
: "";
|
||||||
},
|
},
|
||||||
selectCity(value) {
|
selectCity(value) {
|
||||||
console.log(value);
|
console.log(value);
|
||||||
@@ -165,7 +168,8 @@ export default {
|
|||||||
this.entity.selected.postcode.name = value.name;
|
this.entity.selected.postcode.name = value.name;
|
||||||
this.entity.selected.postcode.code = value.code;
|
this.entity.selected.postcode.code = value.code;
|
||||||
if (value.center) {
|
if (value.center) {
|
||||||
this.entity.selected.postcode.coordinates = value.center.coordinates;
|
this.entity.selected.postcode.coordinates =
|
||||||
|
value.center.coordinates;
|
||||||
}
|
}
|
||||||
this.entity.selected.writeNew.postcode = false;
|
this.entity.selected.writeNew.postcode = false;
|
||||||
this.$emit("getReferenceAddresses", value);
|
this.$emit("getReferenceAddresses", value);
|
||||||
@@ -186,7 +190,8 @@ export default {
|
|||||||
.then(
|
.then(
|
||||||
(cities) =>
|
(cities) =>
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
this.entity.loaded.cities = cities.results.filter(
|
this.entity.loaded.cities =
|
||||||
|
cities.results.filter(
|
||||||
(c) => c.origin !== 3,
|
(c) => c.origin !== 3,
|
||||||
); // filter out user-defined cities
|
); // filter out user-defined cities
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
@@ -205,7 +210,8 @@ export default {
|
|||||||
.then(
|
.then(
|
||||||
(cities) =>
|
(cities) =>
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
this.entity.loaded.cities = cities.results.filter(
|
this.entity.loaded.cities =
|
||||||
|
cities.results.filter(
|
||||||
(c) => c.origin !== 3,
|
(c) => c.origin !== 3,
|
||||||
); // filter out user-defined cities
|
); // filter out user-defined cities
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
|
@@ -44,7 +44,8 @@ export default {
|
|||||||
ADDRESS_SELECT_COUNTRY,
|
ADDRESS_SELECT_COUNTRY,
|
||||||
trans,
|
trans,
|
||||||
};
|
};
|
||||||
},props: ["context", "entity", "flag", "checkErrors"],
|
},
|
||||||
|
props: ["context", "entity", "flag", "checkErrors"],
|
||||||
emits: ["getCities"],
|
emits: ["getCities"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -59,8 +60,12 @@ export default {
|
|||||||
sortedCountries() {
|
sortedCountries() {
|
||||||
const countries = this.entity.loaded.countries;
|
const countries = this.entity.loaded.countries;
|
||||||
let sortedCountries = [];
|
let sortedCountries = [];
|
||||||
sortedCountries.push(...countries.filter((c) => c.countryCode === "FR"));
|
sortedCountries.push(
|
||||||
sortedCountries.push(...countries.filter((c) => c.countryCode === "BE"));
|
...countries.filter((c) => c.countryCode === "FR"),
|
||||||
|
);
|
||||||
|
sortedCountries.push(
|
||||||
|
...countries.filter((c) => c.countryCode === "BE"),
|
||||||
|
);
|
||||||
sortedCountries.push(
|
sortedCountries.push(
|
||||||
...countries
|
...countries
|
||||||
.filter((c) => c.countryCode !== "FR")
|
.filter((c) => c.countryCode !== "FR")
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="insideModal === false" class="loading">
|
<div v-if="insideModal === false" class="loading">
|
||||||
<i v-if="flag.loading" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw" />
|
<i
|
||||||
|
v-if="flag.loading"
|
||||||
|
class="fa fa-circle-o-notch fa-spin fa-2x fa-fw"
|
||||||
|
/>
|
||||||
<span class="sr-only">{{ $t("loading") }}</span>
|
<span class="sr-only">{{ $t("loading") }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -139,7 +142,8 @@ export default {
|
|||||||
address["street"] = this.entity.selected.address.street
|
address["street"] = this.entity.selected.address.street
|
||||||
? this.entity.selected.address.street
|
? this.entity.selected.address.street
|
||||||
: null;
|
: null;
|
||||||
address["streetNumber"] = this.entity.selected.address.streetNumber
|
address["streetNumber"] = this.entity.selected.address
|
||||||
|
.streetNumber
|
||||||
? this.entity.selected.address.streetNumber
|
? this.entity.selected.address.streetNumber
|
||||||
: null;
|
: null;
|
||||||
address["floor"] = this.entity.selected.address.floor
|
address["floor"] = this.entity.selected.address.floor
|
||||||
@@ -154,10 +158,12 @@ export default {
|
|||||||
address["flat"] = this.entity.selected.address.flat
|
address["flat"] = this.entity.selected.address.flat
|
||||||
? this.entity.selected.address.flat
|
? this.entity.selected.address.flat
|
||||||
: null;
|
: null;
|
||||||
address["buildingName"] = this.entity.selected.address.buildingName
|
address["buildingName"] = this.entity.selected.address
|
||||||
|
.buildingName
|
||||||
? this.entity.selected.address.buildingName
|
? this.entity.selected.address.buildingName
|
||||||
: null;
|
: null;
|
||||||
address["distribution"] = this.entity.selected.address.distribution
|
address["distribution"] = this.entity.selected.address
|
||||||
|
.distribution
|
||||||
? this.entity.selected.address.distribution
|
? this.entity.selected.address.distribution
|
||||||
: null;
|
: null;
|
||||||
address["extra"] = this.entity.selected.address.extra
|
address["extra"] = this.entity.selected.address.extra
|
||||||
|
@@ -2,7 +2,10 @@
|
|||||||
<div class="address-form">
|
<div class="address-form">
|
||||||
<!-- Not display in modal -->
|
<!-- Not display in modal -->
|
||||||
<div v-if="insideModal === false" class="loading">
|
<div v-if="insideModal === false" class="loading">
|
||||||
<i v-if="flag.loading" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw" />
|
<i
|
||||||
|
v-if="flag.loading"
|
||||||
|
class="fa fa-circle-o-notch fa-spin fa-2x fa-fw"
|
||||||
|
/>
|
||||||
<span class="sr-only">Loading...</span>
|
<span class="sr-only">Loading...</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -129,7 +132,8 @@ export default {
|
|||||||
ADDRESS_IS_CONFIDENTIAL,
|
ADDRESS_IS_CONFIDENTIAL,
|
||||||
ADDRESS_IS_NO_ADDRESS,
|
ADDRESS_IS_NO_ADDRESS,
|
||||||
};
|
};
|
||||||
},props: [
|
},
|
||||||
|
props: [
|
||||||
"context",
|
"context",
|
||||||
"options",
|
"options",
|
||||||
"defaultz",
|
"defaultz",
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="!onlyButton" class="mt-4 flex-grow-1">
|
<div v-if="!onlyButton" class="mt-4 flex-grow-1">
|
||||||
<div class="loading">
|
<div class="loading">
|
||||||
<i v-if="flag.loading" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw" />
|
<i
|
||||||
|
v-if="flag.loading"
|
||||||
|
class="fa fa-circle-o-notch fa-spin fa-2x fa-fw"
|
||||||
|
/>
|
||||||
<span class="sr-only">{{ trans(ADDRESS_LOADING) }}</span>
|
<span class="sr-only">{{ trans(ADDRESS_LOADING) }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -44,7 +47,9 @@
|
|||||||
name="button"
|
name="button"
|
||||||
:title="trans(getTextButton)"
|
:title="trans(getTextButton)"
|
||||||
>
|
>
|
||||||
<span v-if="displayTextButton">{{ trans(getTextButton) }}</span>
|
<span v-if="displayTextButton">{{
|
||||||
|
trans(getTextButton)
|
||||||
|
}}</span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
</action-buttons>
|
</action-buttons>
|
||||||
@@ -57,7 +62,9 @@
|
|||||||
:use-date-pane="useDatePane"
|
:use-date-pane="useDatePane"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div v-if="this.context.target.name === 'household' || this.context.edit">
|
<div
|
||||||
|
v-if="this.context.target.name === 'household' || this.context.edit"
|
||||||
|
>
|
||||||
<action-buttons :options="this.options" :defaultz="this.defaultz">
|
<action-buttons :options="this.options" :defaultz="this.defaultz">
|
||||||
<template #action>
|
<template #action>
|
||||||
<button
|
<button
|
||||||
@@ -68,7 +75,9 @@
|
|||||||
name="button"
|
name="button"
|
||||||
:title="trans(getTextButton)"
|
:title="trans(getTextButton)"
|
||||||
>
|
>
|
||||||
<span v-if="displayTextButton">{{ trans(getTextButton) }}</span>
|
<span v-if="displayTextButton">{{
|
||||||
|
trans(getTextButton)
|
||||||
|
}}</span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
</action-buttons>
|
</action-buttons>
|
||||||
@@ -90,7 +99,9 @@
|
|||||||
name="button"
|
name="button"
|
||||||
:title="trans(getTextButton)"
|
:title="trans(getTextButton)"
|
||||||
>
|
>
|
||||||
<span v-if="displayTextButton">{{ trans(getTextButton) }}</span>
|
<span v-if="displayTextButton">{{
|
||||||
|
trans(getTextButton)
|
||||||
|
}}</span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
</action-buttons>
|
</action-buttons>
|
||||||
@@ -113,7 +124,8 @@ import {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ShowPane",
|
name: "ShowPane",
|
||||||
methods: {},components: {
|
methods: {},
|
||||||
|
components: {
|
||||||
AddressRenderBox,
|
AddressRenderBox,
|
||||||
ActionButtons,
|
ActionButtons,
|
||||||
},
|
},
|
||||||
@@ -128,7 +140,8 @@ export default {
|
|||||||
ADDRESS_ADDRESS_NEW_SUCCESS,
|
ADDRESS_ADDRESS_NEW_SUCCESS,
|
||||||
ADDRESS_ADDRESS_EDIT_SUCCESS,
|
ADDRESS_ADDRESS_EDIT_SUCCESS,
|
||||||
};
|
};
|
||||||
},props: [
|
},
|
||||||
|
props: [
|
||||||
"context",
|
"context",
|
||||||
"defaultz",
|
"defaultz",
|
||||||
"options",
|
"options",
|
||||||
@@ -179,7 +192,9 @@ export default {
|
|||||||
: this.defaultz.button.text.create;
|
: this.defaultz.button.text.create;
|
||||||
},
|
},
|
||||||
getSuccessText() {
|
getSuccessText() {
|
||||||
return this.context.edit ? ADDRESS_ADDRESS_EDIT_SUCCESS : ADDRESS_ADDRESS_NEW_SUCCESS;
|
return this.context.edit
|
||||||
|
? ADDRESS_ADDRESS_EDIT_SUCCESS
|
||||||
|
: ADDRESS_ADDRESS_NEW_SUCCESS;
|
||||||
},
|
},
|
||||||
onlyButton() {
|
onlyButton() {
|
||||||
return typeof this.options.onlyButton !== "undefined"
|
return typeof this.options.onlyButton !== "undefined"
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="insideModal === false" class="loading">
|
<div v-if="insideModal === false" class="loading">
|
||||||
<i v-if="flag.loading" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw" />
|
<i
|
||||||
|
v-if="flag.loading"
|
||||||
|
class="fa fa-circle-o-notch fa-spin fa-2x fa-fw"
|
||||||
|
/>
|
||||||
<span class="sr-only">{{ $t("loading") }}</span>
|
<span class="sr-only">{{ $t("loading") }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -86,7 +86,10 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="waiting-screen">
|
<div id="waiting-screen">
|
||||||
<div v-if="isPending && isFetching" class="alert alert-danger text-center">
|
<div
|
||||||
|
v-if="isPending && isFetching"
|
||||||
|
class="alert alert-danger text-center"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
{{ trans(EXPORT_GENERATION_EXPORT_GENERATION_IS_PENDING) }}
|
{{ trans(EXPORT_GENERATION_EXPORT_GENERATION_IS_PENDING) }}
|
||||||
|
@@ -1,156 +1,155 @@
|
|||||||
<template>
|
<template>
|
||||||
<h2>{{ trans(MAIN_TITLE) }}</h2>
|
<h2>{{ $t("main_title") }}</h2>
|
||||||
|
|
||||||
<ul class="nav nav-tabs">
|
<ul class="nav nav-tabs">
|
||||||
<li v-for="tab in displayedTabs" :key="tab.key" class="nav-item">
|
<li class="nav-item">
|
||||||
<a
|
<a
|
||||||
class="nav-link"
|
class="nav-link"
|
||||||
:class="{ active: activeTab === tab.key }"
|
:class="{ active: activeTab === 'MyCustoms' }"
|
||||||
@click="selectTab(tab.key)"
|
@click="selectTab('MyCustoms')"
|
||||||
>
|
>
|
||||||
<i v-if="tab.icon" :class="tab.icon" />
|
<i class="fa fa-dashboard" />
|
||||||
<span v-else>{{ tab.label }}</span>
|
</a>
|
||||||
<tab-counter v-if="tab.counter" :count="tab.counter()" />
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a
|
||||||
|
class="nav-link"
|
||||||
|
:class="{ active: activeTab === 'MyNotifications' }"
|
||||||
|
@click="selectTab('MyNotifications')"
|
||||||
|
>
|
||||||
|
{{ $t("my_notifications.tab") }}
|
||||||
|
<tab-counter :count="state.notifications.count" />
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a
|
||||||
|
class="nav-link"
|
||||||
|
:class="{ active: activeTab === 'MyAccompanyingCourses' }"
|
||||||
|
@click="selectTab('MyAccompanyingCourses')"
|
||||||
|
>
|
||||||
|
{{ $t("my_accompanying_courses.tab") }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<!-- <li class="nav-item">
|
||||||
|
<a class="nav-link"
|
||||||
|
:class="{'active': activeTab === 'MyWorks'}"
|
||||||
|
@click="selectTab('MyWorks')">
|
||||||
|
{{ $t('my_works.tab') }}
|
||||||
|
<tab-counter :count="state.works.count"></tab-counter>
|
||||||
|
</a>
|
||||||
|
</li> -->
|
||||||
|
<li class="nav-item">
|
||||||
|
<a
|
||||||
|
class="nav-link"
|
||||||
|
:class="{ active: activeTab === 'MyEvaluations' }"
|
||||||
|
@click="selectTab('MyEvaluations')"
|
||||||
|
>
|
||||||
|
{{ $t("my_evaluations.tab") }}
|
||||||
|
<tab-counter :count="state.evaluations.count" />
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a
|
||||||
|
class="nav-link"
|
||||||
|
:class="{ active: activeTab === 'MyTasks' }"
|
||||||
|
@click="selectTab('MyTasks')"
|
||||||
|
>
|
||||||
|
{{ $t("my_tasks.tab") }}
|
||||||
|
<tab-counter
|
||||||
|
:count="state.tasks.warning.count + state.tasks.alert.count"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a
|
||||||
|
class="nav-link"
|
||||||
|
:class="{ active: activeTab === 'MyWorkflows' }"
|
||||||
|
@click="selectTab('MyWorkflows')"
|
||||||
|
>
|
||||||
|
{{ $t("my_workflows.tab") }}
|
||||||
|
<tab-counter
|
||||||
|
:count="state.workflows.count + state.workflowsCc.count"
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item loading ms-auto py-2" v-if="loading">
|
<li class="nav-item loading ms-auto py-2" v-if="loading">
|
||||||
<i
|
<i
|
||||||
class="fa fa-circle-o-notch fa-spin fa-lg text-chill-gray"
|
class="fa fa-circle-o-notch fa-spin fa-lg text-chill-gray"
|
||||||
:title="trans(LOADING)"
|
:title="$t('loading')"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="my-4">
|
<div class="my-4">
|
||||||
<MyCustoms v-if="activeTab === HomepageTabs.MyCustoms" />
|
<my-customs v-if="activeTab === 'MyCustoms'" />
|
||||||
<MyTickets v-else-if="activeTab === HomepageTabs.MyTickets" />
|
<my-works v-else-if="activeTab === 'MyWorks'" />
|
||||||
<MyNotifications v-else-if="activeTab === HomepageTabs.MyNotifications" />
|
<my-evaluations v-else-if="activeTab === 'MyEvaluations'" />
|
||||||
<MyAccompanyingCourses
|
<my-tasks v-else-if="activeTab === 'MyTasks'" />
|
||||||
v-else-if="activeTab === HomepageTabs.MyAccompanyingCourses"
|
<my-accompanying-courses
|
||||||
|
v-else-if="activeTab === 'MyAccompanyingCourses'"
|
||||||
/>
|
/>
|
||||||
<MyEvaluations v-else-if="activeTab === HomepageTabs.MyEvaluations" />
|
<my-notifications v-else-if="activeTab === 'MyNotifications'" />
|
||||||
<MyTasks v-else-if="activeTab === HomepageTabs.MyTasks" />
|
<my-workflows v-else-if="activeTab === 'MyWorkflows'" />
|
||||||
<MyWorkflows v-else-if="activeTab === HomepageTabs.MyWorkflows" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script>
|
||||||
import { ref, computed, onMounted } from "vue";
|
import MyCustoms from "./MyCustoms";
|
||||||
import { useStore } from "vuex";
|
import MyWorks from "./MyWorks";
|
||||||
|
import MyEvaluations from "./MyEvaluations";
|
||||||
// Components
|
import MyTasks from "./MyTasks";
|
||||||
import MyCustoms from "./MyCustoms.vue";
|
import MyAccompanyingCourses from "./MyAccompanyingCourses";
|
||||||
import MyEvaluations from "./MyEvaluations.vue";
|
import MyNotifications from "./MyNotifications";
|
||||||
import MyTasks from "./MyTasks.vue";
|
|
||||||
import MyAccompanyingCourses from "./MyAccompanyingCourses.vue";
|
|
||||||
import MyNotifications from "./MyNotifications.vue";
|
|
||||||
import MyWorkflows from "./MyWorkflows.vue";
|
import MyWorkflows from "./MyWorkflows.vue";
|
||||||
import MyTickets from "./MyTickets.vue";
|
import TabCounter from "./TabCounter";
|
||||||
import TabCounter from "./TabCounter.vue";
|
import { mapState } from "vuex";
|
||||||
|
|
||||||
// Translations
|
export default {
|
||||||
import {
|
name: "App",
|
||||||
MAIN_TITLE,
|
components: {
|
||||||
MY_TICKETS_TAB,
|
MyCustoms,
|
||||||
MY_EVALUATIONS_TAB,
|
MyWorks,
|
||||||
MY_TASKS_TAB,
|
MyEvaluations,
|
||||||
MY_ACCOMPANYING_COURSES_TAB,
|
MyTasks,
|
||||||
MY_NOTIFICATIONS_TAB,
|
MyWorkflows,
|
||||||
MY_WORKFLOWS_TAB,
|
MyAccompanyingCourses,
|
||||||
LOADING,
|
MyNotifications,
|
||||||
trans,
|
TabCounter,
|
||||||
} from "translator";
|
|
||||||
|
|
||||||
// Types
|
|
||||||
import {
|
|
||||||
HomepageConfig,
|
|
||||||
HomepageTabs,
|
|
||||||
TabDefinition,
|
|
||||||
} from "ChillMainAssets/types";
|
|
||||||
|
|
||||||
const store = useStore();
|
|
||||||
|
|
||||||
defineExpose({ HomepageTabs });
|
|
||||||
|
|
||||||
const homepageConfig = ref<HomepageConfig>(JSON.parse(window.homepage_config));
|
|
||||||
const state = computed(() => store.state.homepage);
|
|
||||||
const ticketListState = computed(() => store.state.ticketList);
|
|
||||||
|
|
||||||
const tabDefinitions: TabDefinition[] = [
|
|
||||||
{
|
|
||||||
key: HomepageTabs.MyCustoms,
|
|
||||||
label: "",
|
|
||||||
icon: "fa fa-dashboard",
|
|
||||||
counter: () => 0,
|
|
||||||
},
|
},
|
||||||
{
|
data() {
|
||||||
key: HomepageTabs.MyTickets,
|
return {
|
||||||
label: trans(MY_TICKETS_TAB),
|
activeTab: "MyCustoms",
|
||||||
icon: null,
|
};
|
||||||
counter: () => ticketListState.value?.count,
|
|
||||||
},
|
},
|
||||||
{
|
computed: {
|
||||||
key: HomepageTabs.MyNotifications,
|
...mapState(["loading"]),
|
||||||
label: trans(MY_NOTIFICATIONS_TAB),
|
// just to see all in devtool :
|
||||||
icon: null,
|
...mapState({
|
||||||
counter: () => state.value?.notifications?.count,
|
state: (state) => state,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
methods: {
|
||||||
key: HomepageTabs.MyAccompanyingCourses,
|
selectTab(tab) {
|
||||||
label: trans(MY_ACCOMPANYING_COURSES_TAB),
|
if (tab !== "MyCustoms") {
|
||||||
icon: null,
|
this.$store.dispatch("getByTab", { tab: tab });
|
||||||
counter: () => state.value?.accompanyingCourses?.count,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: HomepageTabs.MyEvaluations,
|
|
||||||
label: trans(MY_EVALUATIONS_TAB),
|
|
||||||
icon: null,
|
|
||||||
counter: () => state.value?.evaluations?.count,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: HomepageTabs.MyTasks,
|
|
||||||
label: trans(MY_TASKS_TAB),
|
|
||||||
icon: null,
|
|
||||||
counter: () =>
|
|
||||||
state.value?.tasks?.warning?.count + state.value?.tasks?.alert?.count,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: HomepageTabs.MyWorkflows,
|
|
||||||
label: trans(MY_WORKFLOWS_TAB),
|
|
||||||
icon: null,
|
|
||||||
counter: () =>
|
|
||||||
state.value?.workflows?.count + state.value?.workflowsCc?.count,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const displayedTabs = computed(() => {
|
|
||||||
// Always show MyCustoms first if present
|
|
||||||
const tabs = [] as TabDefinition[];
|
|
||||||
for (const tabEnum of homepageConfig.value.displayTabs) {
|
|
||||||
const def = tabDefinitions.find(
|
|
||||||
(t) => t.key === Number(HomepageTabs[tabEnum]),
|
|
||||||
);
|
|
||||||
if (def) tabs.push(def);
|
|
||||||
}
|
}
|
||||||
return tabs.filter(Boolean);
|
this.activeTab = tab;
|
||||||
});
|
console.log(this.activeTab);
|
||||||
|
},
|
||||||
const activeTab = ref(Number(HomepageTabs[homepageConfig.value.defaultTab]));
|
},
|
||||||
|
mounted() {
|
||||||
const loading = computed(() => store.state.loading);
|
for (const m of [
|
||||||
|
"MyNotifications",
|
||||||
function selectTab(tab: HomepageTabs) {
|
"MyAccompanyingCourses",
|
||||||
if (tab !== HomepageTabs.MyCustoms) {
|
// 'MyWorks',
|
||||||
store.dispatch("getByTab", { tab: tab });
|
"MyEvaluations",
|
||||||
|
"MyTasks",
|
||||||
|
"MyWorkflows",
|
||||||
|
]) {
|
||||||
|
this.$store.dispatch("getByTab", { tab: m, param: "countOnly=1" });
|
||||||
}
|
}
|
||||||
activeTab.value = tab;
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
for (const tab of displayedTabs.value) {
|
|
||||||
if (tab.key !== HomepageTabs.MyCustoms) {
|
|
||||||
store.dispatch("getByTab", { tab: tab.key, param: "countOnly=1" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@@ -25,9 +25,11 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #body>
|
<template #body>
|
||||||
<p class="news-date">
|
<p class="news-date">
|
||||||
<time class="createdBy" datetime="{{item.startDate.datetime}}">{{
|
<time
|
||||||
$d(newsItemStartDate(), "text")
|
class="createdBy"
|
||||||
}}</time>
|
datetime="{{item.startDate.datetime}}"
|
||||||
|
>{{ $d(newsItemStartDate(), "text") }}</time
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
<div v-html="convertMarkdownToHtml(item.content)"></div>
|
<div v-html="convertMarkdownToHtml(item.content)"></div>
|
||||||
</template>
|
</template>
|
||||||
@@ -91,7 +93,10 @@ const truncateContent = (content: string): string => {
|
|||||||
|
|
||||||
// Truncate if amount of lines are too many
|
// Truncate if amount of lines are too many
|
||||||
if (lines.length > props.maxLines && content.length < props.maxLength) {
|
if (lines.length > props.maxLines && content.length < props.maxLength) {
|
||||||
const truncatedContent = lines.slice(0, props.maxLines).join("\n").trim();
|
const truncatedContent = lines
|
||||||
|
.slice(0, props.maxLines)
|
||||||
|
.join("\n")
|
||||||
|
.trim();
|
||||||
return truncatedContent + "...";
|
return truncatedContent + "...";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +125,8 @@ const truncateContent = (content: string): string => {
|
|||||||
if (linkStartIndex !== -1) {
|
if (linkStartIndex !== -1) {
|
||||||
const linkEndIndex = content.indexOf(")", linkStartIndex);
|
const linkEndIndex = content.indexOf(")", linkStartIndex);
|
||||||
const url = content.slice(linkStartIndex + 1, linkEndIndex);
|
const url = content.slice(linkStartIndex + 1, linkEndIndex);
|
||||||
truncatedContent = truncatedContent.slice(0, linkStartIndex) + `(${url})`;
|
truncatedContent =
|
||||||
|
truncatedContent.slice(0, linkStartIndex) + `(${url})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
truncatedContent += "...";
|
truncatedContent += "...";
|
||||||
|
@@ -1,40 +1,47 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="alert alert-light">
|
<div class="alert alert-light">
|
||||||
{{ trans(MY_ACCOMPANYING_COURSES_DESCRIPTION) }}
|
{{ $t("my_accompanying_courses.description") }}
|
||||||
</div>
|
</div>
|
||||||
<span v-if="noResults" class="chill-no-data-statement">
|
<span v-if="noResults" class="chill-no-data-statement">{{
|
||||||
{{ trans(NO_DATA) }}
|
$t("no_data")
|
||||||
</span>
|
}}</span>
|
||||||
<tab-table v-else>
|
<tab-table v-else>
|
||||||
<template #thead>
|
<template #thead>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(OPENING_DATE) }}
|
{{ $t("opening_date") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(SOCIAL_ISSUES) }}
|
{{ $t("social_issues") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(CONCERNED_PERSONS) }}
|
{{ $t("concerned_persons") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" />
|
<th scope="col" />
|
||||||
<th scope="col" />
|
<th scope="col" />
|
||||||
</template>
|
</template>
|
||||||
<template #tbody>
|
<template #tbody>
|
||||||
<tr v-for="(c, i) in accompanyingCourses.results" :key="`course-${i}`">
|
<tr
|
||||||
<td>{{ $d(new Date(c.openingDate.datetime), "short") }}</td>
|
v-for="(c, i) in accompanyingCourses.results"
|
||||||
|
:key="`course-${i}`"
|
||||||
|
>
|
||||||
|
<td>{{ $d(c.openingDate.datetime, "short") }}</td>
|
||||||
<td>
|
<td>
|
||||||
<span
|
<span
|
||||||
v-for="(issue, index) in c.socialIssues"
|
v-for="(i, index) in c.socialIssues"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="chill-entity entity-social-issue"
|
class="chill-entity entity-social-issue"
|
||||||
>
|
>
|
||||||
<span class="badge bg-chill-l-gray text-dark">
|
<span class="badge bg-chill-l-gray text-dark">
|
||||||
{{ localizeString(issue.title) }}
|
{{ localizeString(i.title) }}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span v-for="p in c.participations" class="me-1" :key="p.person.id">
|
<span
|
||||||
|
v-for="p in c.participations"
|
||||||
|
class="me-1"
|
||||||
|
:key="p.person.id"
|
||||||
|
>
|
||||||
<on-the-fly
|
<on-the-fly
|
||||||
:type="p.person.type"
|
:type="p.person.type"
|
||||||
:id="p.person.id"
|
:id="p.person.id"
|
||||||
@@ -45,16 +52,20 @@
|
|||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span v-if="c.emergency" class="badge rounded-pill bg-danger me-1">{{
|
<span
|
||||||
trans(EMERGENCY)
|
v-if="c.emergency"
|
||||||
}}</span>
|
class="badge rounded-pill bg-danger me-1"
|
||||||
<span v-if="c.confidential" class="badge rounded-pill bg-danger">{{
|
>{{ $t("emergency") }}</span
|
||||||
trans(CONFIDENTIAL)
|
>
|
||||||
}}</span>
|
<span
|
||||||
|
v-if="c.confidential"
|
||||||
|
class="badge rounded-pill bg-danger"
|
||||||
|
>{{ $t("confidential") }}</span
|
||||||
|
>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-sm btn-show" :href="getUrl(c)">
|
<a class="btn btn-sm btn-show" :href="getUrl(c)">
|
||||||
{{ trans(SHOW_ENTITY, { entity: trans(THE_COURSE) }) }}
|
{{ $t("show_entity", { entity: $t("the_course") }) }}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -62,45 +73,36 @@
|
|||||||
</tab-table>
|
</tab-table>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script>
|
||||||
import { computed, ComputedRef } from "vue";
|
import { mapState, mapGetters } from "vuex";
|
||||||
import { useStore } from "vuex";
|
import TabTable from "./TabTable";
|
||||||
import TabTable from "./TabTable.vue";
|
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly";
|
||||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
|
||||||
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||||
import { AccompanyingCourse } from "ChillPersonAssets/types";
|
|
||||||
import { PaginationResponse } from "ChillMainAssets/lib/api/apiMethods";
|
|
||||||
import {
|
|
||||||
MY_ACCOMPANYING_COURSES_DESCRIPTION,
|
|
||||||
OPENING_DATE,
|
|
||||||
SOCIAL_ISSUES,
|
|
||||||
CONCERNED_PERSONS,
|
|
||||||
SHOW_ENTITY,
|
|
||||||
THE_COURSE,
|
|
||||||
NO_DATA,
|
|
||||||
EMERGENCY,
|
|
||||||
CONFIDENTIAL,
|
|
||||||
trans,
|
|
||||||
} from "translator";
|
|
||||||
const store = useStore();
|
|
||||||
|
|
||||||
const accompanyingCourses: ComputedRef<PaginationResponse<AccompanyingCourse>> =
|
export default {
|
||||||
computed(() => store.state.homepage.accompanyingCourses);
|
name: "MyAccompanyingCourses",
|
||||||
const isAccompanyingCoursesLoaded = computed(
|
components: {
|
||||||
() => store.getters.isAccompanyingCoursesLoaded,
|
TabTable,
|
||||||
);
|
OnTheFly,
|
||||||
|
},
|
||||||
const noResults = computed(() => {
|
computed: {
|
||||||
if (!isAccompanyingCoursesLoaded.value) {
|
...mapState(["accompanyingCourses"]),
|
||||||
|
...mapGetters(["isAccompanyingCoursesLoaded"]),
|
||||||
|
noResults() {
|
||||||
|
if (!this.isAccompanyingCoursesLoaded) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return accompanyingCourses.value.count === 0;
|
return this.accompanyingCourses.count === 0;
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
},
|
||||||
function getUrl(c: { id: number }): string {
|
methods: {
|
||||||
|
localizeString,
|
||||||
|
getUrl(c) {
|
||||||
return `/fr/parcours/${c.id}`;
|
return `/fr/parcours/${c.id}`;
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@@ -1,72 +1,95 @@
|
|||||||
<template>
|
<template>
|
||||||
<span v-if="noResults" class="chill-no-data-statement">
|
<span v-if="noResults" class="chill-no-data-statement">{{
|
||||||
{{ trans(NO_DASHBOARD) }}
|
$t("no_dashboard")
|
||||||
</span>
|
}}</span>
|
||||||
<div v-else id="dashboards" class="container g-3">
|
<div v-else id="dashboards" class="container g-3">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="mbloc col-xs-12 col-sm-4">
|
<div class="mbloc col-xs-12 col-sm-4">
|
||||||
<div class="custom1">
|
<div class="custom1">
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li v-if="(counter.value?.notifications || 0) > 0">
|
<li v-if="counter.notifications > 0">
|
||||||
<span :class="counterClass">
|
<i18n-t
|
||||||
{{
|
keypath="counter.unread_notifications"
|
||||||
trans(COUNTER_UNREAD_NOTIFICATIONS, {
|
tag="span"
|
||||||
n: counter.value?.notifications || 0,
|
:class="counterClass"
|
||||||
})
|
:plural="counter.notifications"
|
||||||
}}
|
>
|
||||||
</span>
|
<template #n>
|
||||||
|
<span>{{ counter.notifications }}</span>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="(counter.value?.accompanyingCourses || 0) > 0">
|
<li v-if="counter.accompanyingCourses > 0">
|
||||||
<span :class="counterClass">
|
<i18n-t
|
||||||
{{
|
keypath="counter.assignated_courses"
|
||||||
trans(COUNTER_ASSIGNATED_COURSES, {
|
tag="span"
|
||||||
n: counter.value?.accompanyingCourses || 0,
|
:class="counterClass"
|
||||||
})
|
:plural="counter.accompanyingCourses"
|
||||||
}}
|
>
|
||||||
</span>
|
<template #n>
|
||||||
|
<span>{{
|
||||||
|
counter.accompanyingCourses
|
||||||
|
}}</span>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="(counter.value?.works || 0) > 0">
|
<li v-if="counter.works > 0">
|
||||||
<span :class="counterClass">
|
<i18n-t
|
||||||
{{
|
keypath="counter.assignated_actions"
|
||||||
trans(COUNTER_ASSIGNATED_ACTIONS, {
|
tag="span"
|
||||||
n: counter.value?.works || 0,
|
:class="counterClass"
|
||||||
})
|
:plural="counter.works"
|
||||||
}}
|
>
|
||||||
</span>
|
<template #n>
|
||||||
|
<span>{{ counter.works }}</span>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="(counter.value?.evaluations || 0) > 0">
|
<li v-if="counter.evaluations > 0">
|
||||||
<span :class="counterClass">
|
<i18n-t
|
||||||
{{
|
keypath="counter.assignated_evaluations"
|
||||||
trans(COUNTER_ASSIGNATED_EVALUATIONS, {
|
tag="span"
|
||||||
n: counter.value?.evaluations || 0,
|
:class="counterClass"
|
||||||
})
|
:plural="counter.evaluations"
|
||||||
}}
|
>
|
||||||
</span>
|
<template #n>
|
||||||
|
<span>{{ counter.evaluations }}</span>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="(counter.value?.tasksAlert || 0) > 0">
|
<li v-if="counter.tasksAlert > 0">
|
||||||
<span :class="counterClass">
|
<i18n-t
|
||||||
{{
|
keypath="counter.alert_tasks"
|
||||||
trans(COUNTER_ALERT_TASKS, {
|
tag="span"
|
||||||
n: counter.value?.tasksAlert || 0,
|
:class="counterClass"
|
||||||
})
|
:plural="counter.tasksAlert"
|
||||||
}}
|
>
|
||||||
</span>
|
<template #n>
|
||||||
|
<span>{{ counter.tasksAlert }}</span>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="(counter.value?.tasksWarning || 0) > 0">
|
<li v-if="counter.tasksWarning > 0">
|
||||||
<span :class="counterClass">
|
<i18n-t
|
||||||
{{
|
keypath="counter.warning_tasks"
|
||||||
trans(COUNTER_WARNING_TASKS, {
|
tag="span"
|
||||||
n: counter.value?.tasksWarning || 0,
|
:class="counterClass"
|
||||||
})
|
:plural="counter.tasksWarning"
|
||||||
}}
|
>
|
||||||
</span>
|
<template #n>
|
||||||
|
<span>{{ counter.tasksWarning }}</span>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-if="hasDashboardItems">
|
<template v-if="this.hasDashboardItems">
|
||||||
<template v-for="(dashboardItem, index) in dashboardItems" :key="index">
|
<template
|
||||||
|
v-for="(dashboardItem, index) in this.dashboardItems"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="mbloc col-xs-12 col-sm-8 news"
|
class="mbloc col-xs-12 col-sm-8 news"
|
||||||
v-if="dashboardItem.type === 'news'"
|
v-if="dashboardItem.type === 'news'"
|
||||||
@@ -79,53 +102,44 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script>
|
||||||
import { ref, computed, onMounted } from "vue";
|
import { mapGetters } from "vuex";
|
||||||
import { useStore } from "vuex";
|
|
||||||
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
||||||
import News from "./DashboardWidgets/News.vue";
|
import News from "./DashboardWidgets/News.vue";
|
||||||
import {
|
|
||||||
NO_DASHBOARD,
|
|
||||||
COUNTER_UNREAD_NOTIFICATIONS,
|
|
||||||
COUNTER_ASSIGNATED_COURSES,
|
|
||||||
COUNTER_ASSIGNATED_ACTIONS,
|
|
||||||
COUNTER_ASSIGNATED_EVALUATIONS,
|
|
||||||
COUNTER_ALERT_TASKS,
|
|
||||||
COUNTER_WARNING_TASKS,
|
|
||||||
trans,
|
|
||||||
} from "translator";
|
|
||||||
|
|
||||||
interface MyCustom {
|
export default {
|
||||||
id: number;
|
name: "MyCustoms",
|
||||||
type: string;
|
components: {
|
||||||
metadata: Record<string, unknown>;
|
News,
|
||||||
userId: number;
|
},
|
||||||
position: string;
|
data() {
|
||||||
}
|
return {
|
||||||
|
counterClass: {
|
||||||
const store = useStore();
|
counter: true, //hack to pass class 'counter' in i18n-t
|
||||||
|
},
|
||||||
const counter = computed(() => store.getters.counter);
|
dashboardItems: [],
|
||||||
|
masonry: null,
|
||||||
const counterClass = { counter: true };
|
};
|
||||||
|
},
|
||||||
const dashboardItems = ref<MyCustom[]>([]);
|
computed: {
|
||||||
|
...mapGetters(["counter"]),
|
||||||
const noResults = computed(() => false);
|
noResults() {
|
||||||
|
return false;
|
||||||
const hasDashboardItems = computed(() => dashboardItems.value.length > 0);
|
},
|
||||||
|
hasDashboardItems() {
|
||||||
onMounted(async () => {
|
return this.dashboardItems.length > 0;
|
||||||
try {
|
},
|
||||||
const response: MyCustom[] = await makeFetch(
|
},
|
||||||
"GET",
|
mounted() {
|
||||||
"/api/1.0/main/dashboard-config-item.json",
|
makeFetch("GET", "/api/1.0/main/dashboard-config-item.json")
|
||||||
);
|
.then((response) => {
|
||||||
dashboardItems.value = response;
|
this.dashboardItems = response;
|
||||||
} catch (error) {
|
})
|
||||||
|
.catch((error) => {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@@ -1,50 +1,50 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="accompanying-course-work">
|
<div class="accompanying-course-work">
|
||||||
<div class="alert alert-light">
|
<div class="alert alert-light">
|
||||||
{{ trans(MY_EVALUATIONS_DESCRIPTION) }}
|
{{ $t("my_evaluations.description") }}
|
||||||
</div>
|
</div>
|
||||||
<span v-if="noResults" class="chill-no-data-statement">
|
<span v-if="noResults" class="chill-no-data-statement">{{
|
||||||
{{ trans(NO_DATA) }}
|
$t("no_data")
|
||||||
</span>
|
}}</span>
|
||||||
<tab-table v-else>
|
<tab-table v-else>
|
||||||
<template #thead>
|
<template #thead>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(MAX_DATE) }}
|
{{ $t("max_date") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(EVALUATION) }}
|
{{ $t("evaluation") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(SOCIAL_ACTION) }}
|
{{ $t("SocialAction") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" />
|
<th scope="col" />
|
||||||
</template>
|
</template>
|
||||||
<template #tbody>
|
<template #tbody>
|
||||||
<tr v-for="(e, i) in evaluations.results" :key="`evaluation-${i}`">
|
<tr
|
||||||
|
v-for="(e, i) in evaluations.results"
|
||||||
|
:key="`evaluation-${i}`"
|
||||||
|
>
|
||||||
|
<td>{{ $d(e.maxDate.datetime, "short") }}</td>
|
||||||
<td>
|
<td>
|
||||||
{{
|
{{ localizeString(e.evaluation.title) }}
|
||||||
e.maxDate?.datetime
|
|
||||||
? $d(new Date(e.maxDate.datetime), "short")
|
|
||||||
: ""
|
|
||||||
}}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ localizeString(e.evaluation?.title ?? null) }}
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="chill-entity entity-social-issue">
|
<span class="chill-entity entity-social-issue">
|
||||||
<span class="badge bg-chill-l-gray text-dark">
|
<span class="badge bg-chill-l-gray text-dark">
|
||||||
{{ e.accompanyingPeriodWork?.socialAction?.issue?.text ?? "" }}
|
{{
|
||||||
|
e.accompanyingPeriodWork.socialAction.issue
|
||||||
|
.text
|
||||||
|
}}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<h4 class="badge-title">
|
<h4 class="badge-title">
|
||||||
<span class="title_label" />
|
<span class="title_label" />
|
||||||
<span class="title_action">
|
<span class="title_action">
|
||||||
{{ e.accompanyingPeriodWork?.socialAction?.text ?? "" }}
|
{{ e.accompanyingPeriodWork.socialAction.text }}
|
||||||
</span>
|
</span>
|
||||||
</h4>
|
</h4>
|
||||||
<span
|
<span
|
||||||
v-for="person in e.accompanyingPeriodWork?.persons ?? []"
|
v-for="person in e.accompanyingPeriodWork.persons"
|
||||||
class="me-1"
|
class="me-1"
|
||||||
:key="person.id"
|
:key="person.id"
|
||||||
>
|
>
|
||||||
@@ -58,25 +58,30 @@
|
|||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group-vertical" role="group" aria-label="Actions">
|
<div
|
||||||
|
class="btn-group-vertical"
|
||||||
|
role="group"
|
||||||
|
aria-label="Actions"
|
||||||
|
>
|
||||||
<a class="btn btn-sm btn-show" :href="getUrl(e)">
|
<a class="btn btn-sm btn-show" :href="getUrl(e)">
|
||||||
{{
|
{{
|
||||||
trans(SHOW_ENTITY, {
|
$t("show_entity", {
|
||||||
entity: trans(THE_EVALUATION),
|
entity: $t("the_evaluation"),
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
class="btn btn-sm btn-show"
|
class="btn btn-sm btn-show"
|
||||||
:href="getUrl(e.accompanyingPeriodWork.accompanyingPeriod!)"
|
:href="
|
||||||
v-if="
|
getUrl(
|
||||||
e.accompanyingPeriodWork &&
|
e.accompanyingPeriodWork
|
||||||
e.accompanyingPeriodWork.accompanyingPeriod
|
.accompanyingPeriod,
|
||||||
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
trans(SHOW_ENTITY, {
|
$t("show_entity", {
|
||||||
entity: trans(THE_COURSE),
|
entity: $t("the_course"),
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
</a>
|
</a>
|
||||||
@@ -88,60 +93,36 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script>
|
||||||
import { computed } from "vue";
|
import { mapState, mapGetters } from "vuex";
|
||||||
import { useStore } from "vuex";
|
import TabTable from "./TabTable";
|
||||||
import TabTable from "./TabTable.vue";
|
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly";
|
||||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
|
||||||
import { localizeString } from "../../lib/localizationHelper/localizationHelper";
|
import { localizeString } from "../../lib/localizationHelper/localizationHelper";
|
||||||
|
|
||||||
const store = useStore();
|
export default {
|
||||||
|
name: "MyEvaluations",
|
||||||
import type { ComputedRef } from "vue";
|
components: {
|
||||||
import {
|
TabTable,
|
||||||
AccompanyingPeriod,
|
OnTheFly,
|
||||||
AccompanyingPeriodWorkEvaluation,
|
},
|
||||||
AccompanyingPeriodWork,
|
computed: {
|
||||||
} from "ChillPersonAssets/types";
|
...mapState(["evaluations"]),
|
||||||
import { PaginationResponse } from "ChillMainAssets/lib/api/apiMethods";
|
...mapGetters(["isEvaluationsLoaded"]),
|
||||||
import {
|
noResults() {
|
||||||
MY_EVALUATIONS_DESCRIPTION,
|
if (!this.isEvaluationsLoaded) {
|
||||||
MAX_DATE,
|
|
||||||
EVALUATION,
|
|
||||||
SHOW_ENTITY,
|
|
||||||
THE_COURSE,
|
|
||||||
THE_EVALUATION,
|
|
||||||
SOCIAL_ACTION,
|
|
||||||
NO_DATA,
|
|
||||||
trans,
|
|
||||||
} from "translator";
|
|
||||||
const evaluations: ComputedRef<
|
|
||||||
PaginationResponse<AccompanyingPeriodWorkEvaluation>
|
|
||||||
> = computed(() => store.state.homepage.evaluations);
|
|
||||||
const isEvaluationsLoaded = computed(() => store.getters.isEvaluationsLoaded);
|
|
||||||
|
|
||||||
const noResults = computed(() => {
|
|
||||||
if (!isEvaluationsLoaded.value) {
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return evaluations.value.count === 0;
|
return this.evaluations.count === 0;
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
},
|
||||||
function getUrl(
|
methods: {
|
||||||
e:
|
localizeString,
|
||||||
| AccompanyingPeriodWorkEvaluation
|
getUrl(e) {
|
||||||
| AccompanyingPeriod
|
|
||||||
| AccompanyingPeriodWork,
|
|
||||||
): string {
|
|
||||||
if (!e) {
|
|
||||||
throw "entity is undefined";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("type" in e && typeof e.type === "string") {
|
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
case "accompanying_period_work_evaluation":
|
case "accompanying_period_work_evaluation":
|
||||||
return `/fr/person/accompanying-period/work/${e.accompanyingPeriodWork?.id}/edit#evaluations`;
|
let anchor = "#evaluations";
|
||||||
|
return `/fr/person/accompanying-period/work/${e.accompanyingPeriodWork.id}/edit${anchor}`;
|
||||||
case "accompanying_period_work":
|
case "accompanying_period_work":
|
||||||
return `/fr/person/accompanying-period/work/${e.id}/edit`;
|
return `/fr/person/accompanying-period/work/${e.id}/edit`;
|
||||||
case "accompanying_period":
|
case "accompanying_period":
|
||||||
@@ -149,9 +130,9 @@ function getUrl(
|
|||||||
default:
|
default:
|
||||||
throw "entity type unknown";
|
throw "entity type unknown";
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
return "";
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
@@ -1,26 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="alert alert-light">
|
<div class="alert alert-light">
|
||||||
{{ trans(MY_NOTIFICATIONS_DESCRIPTION) }}
|
{{ $t("my_notifications.description") }}
|
||||||
</div>
|
</div>
|
||||||
<span v-if="noResults" class="chill-no-data-statement">
|
<span v-if="noResults" class="chill-no-data-statement">{{
|
||||||
{{ trans(NO_DATA) }}
|
$t("no_data")
|
||||||
</span>
|
}}</span>
|
||||||
<tab-table v-else>
|
<tab-table v-else>
|
||||||
<template #thead>
|
<template #thead>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(DATE) }}
|
{{ $t("Date") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(SUBJECT) }}
|
{{ $t("Subject") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(FROM) }}
|
{{ $t("From") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" />
|
<th scope="col" />
|
||||||
</template>
|
</template>
|
||||||
<template #tbody>
|
<template #tbody>
|
||||||
<tr v-for="(n, i) in notifications.results" :key="`notify-${i}`">
|
<tr v-for="(n, i) in notifications.results" :key="`notify-${i}`">
|
||||||
<td>{{ $d(new Date(n.date.datetime), "long") }}</td>
|
<td>{{ $d(n.date.datetime, "long") }}</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="unread">
|
<span class="unread">
|
||||||
<i class="fa fa-envelope-o" />
|
<i class="fa fa-envelope-o" />
|
||||||
@@ -31,11 +31,11 @@
|
|||||||
{{ n.sender.text }}
|
{{ n.sender.text }}
|
||||||
</td>
|
</td>
|
||||||
<td v-else>
|
<td v-else>
|
||||||
{{ trans(AUTOMATIC_NOTIFICATION) }}
|
{{ $t("automatic_notification") }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-sm btn-show" :href="getEntityUrl(n)">
|
<a class="btn btn-sm btn-show" :href="getEntityUrl(n)">
|
||||||
{{ trans(SHOW_ENTITY, { entity: getEntityName(n) }) }}
|
{{ $t("show_entity", { entity: getEntityName(n) }) }}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -43,67 +43,48 @@
|
|||||||
</tab-table>
|
</tab-table>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script>
|
||||||
import { computed, ComputedRef } from "vue";
|
import { mapState, mapGetters } from "vuex";
|
||||||
import { useStore } from "vuex";
|
import TabTable from "./TabTable";
|
||||||
import TabTable from "./TabTable.vue";
|
import { appMessages } from "ChillMainAssets/vuejs/HomepageWidget/js/i18n";
|
||||||
import { Notification } from "ChillPersonAssets/types";
|
|
||||||
|
|
||||||
import {
|
export default {
|
||||||
MY_NOTIFICATIONS_DESCRIPTION,
|
name: "MyNotifications",
|
||||||
DATE,
|
components: {
|
||||||
FROM,
|
TabTable,
|
||||||
SUBJECT,
|
},
|
||||||
SHOW_ENTITY,
|
computed: {
|
||||||
THE_ACTIVITY,
|
...mapState(["notifications"]),
|
||||||
THE_COURSE,
|
...mapGetters(["isNotificationsLoaded"]),
|
||||||
THE_ACTION,
|
noResults() {
|
||||||
THE_EVALUATION_DOCUMENT,
|
if (!this.isNotificationsLoaded) {
|
||||||
THE_WORKFLOW,
|
|
||||||
NO_DATA,
|
|
||||||
AUTOMATIC_NOTIFICATION,
|
|
||||||
trans,
|
|
||||||
} from "translator";
|
|
||||||
import { PaginationResponse } from "ChillMainAssets/lib/api/apiMethods";
|
|
||||||
const store = useStore();
|
|
||||||
|
|
||||||
const notifications: ComputedRef<PaginationResponse<Notification>> = computed(
|
|
||||||
() => store.state.homepage.notifications,
|
|
||||||
);
|
|
||||||
const isNotificationsLoaded = computed(
|
|
||||||
() => store.getters.isNotificationsLoaded,
|
|
||||||
);
|
|
||||||
|
|
||||||
const noResults = computed(() => {
|
|
||||||
if (!isNotificationsLoaded.value) {
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return notifications.value.count === 0;
|
return this.notifications.count === 0;
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
},
|
||||||
function getNotificationUrl(n: Notification): string {
|
methods: {
|
||||||
|
getNotificationUrl(n) {
|
||||||
return `/fr/notification/${n.id}/show`;
|
return `/fr/notification/${n.id}/show`;
|
||||||
}
|
},
|
||||||
|
getEntityName(n) {
|
||||||
function getEntityName(n: Notification): string {
|
|
||||||
switch (n.relatedEntityClass) {
|
switch (n.relatedEntityClass) {
|
||||||
case "Chill\\ActivityBundle\\Entity\\Activity":
|
case "Chill\\ActivityBundle\\Entity\\Activity":
|
||||||
return trans(THE_ACTIVITY);
|
return appMessages.fr.the_activity;
|
||||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod":
|
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod":
|
||||||
return trans(THE_COURSE);
|
return appMessages.fr.the_course;
|
||||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork":
|
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork":
|
||||||
return trans(THE_ACTION);
|
return appMessages.fr.the_action;
|
||||||
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluationDocument":
|
case "Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluationDocument":
|
||||||
return trans(THE_EVALUATION_DOCUMENT);
|
return appMessages.fr.the_evaluation_document;
|
||||||
case "Chill\\MainBundle\\Entity\\Workflow\\EntityWorkflow":
|
case "Chill\\MainBundle\\Entity\\Workflow\\EntityWorkflow":
|
||||||
return trans(THE_WORKFLOW);
|
return appMessages.fr.the_workflow;
|
||||||
default:
|
default:
|
||||||
throw "notification type unknown";
|
throw "notification type unknown";
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
getEntityUrl(n) {
|
||||||
function getEntityUrl(n: Notification): string {
|
|
||||||
switch (n.relatedEntityClass) {
|
switch (n.relatedEntityClass) {
|
||||||
case "Chill\\ActivityBundle\\Entity\\Activity":
|
case "Chill\\ActivityBundle\\Entity\\Activity":
|
||||||
return `/fr/activity/${n.relatedEntityId}/show`;
|
return `/fr/activity/${n.relatedEntityId}/show`;
|
||||||
@@ -118,7 +99,9 @@ function getEntityUrl(n: Notification): string {
|
|||||||
default:
|
default:
|
||||||
throw "notification type unknown";
|
throw "notification type unknown";
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@@ -1,38 +1,38 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="alert alert-light">
|
<div class="alert alert-light">
|
||||||
{{ trans(MY_TASKS_DESCRIPTION_WARNING) }}
|
{{ $t("my_tasks.description_warning") }}
|
||||||
</div>
|
</div>
|
||||||
<span v-if="noResultsAlert" class="chill-no-data-statement">
|
<span v-if="noResultsAlert" class="chill-no-data-statement">{{
|
||||||
{{ trans(NO_DATA) }}
|
$t("no_data")
|
||||||
</span>
|
}}</span>
|
||||||
<tab-table v-else>
|
<tab-table v-else>
|
||||||
<template #thead>
|
<template #thead>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(WARNING_DATE) }}
|
{{ $t("warning_date") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(MAX_DATE) }}
|
{{ $t("max_date") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(TASK) }}
|
{{ $t("task") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" />
|
<th scope="col" />
|
||||||
</template>
|
</template>
|
||||||
<template #tbody>
|
<template #tbody>
|
||||||
<tr v-for="(t, i) in tasks.alert.results" :key="`task-alert-${i}`">
|
<tr v-for="(t, i) in tasks.alert.results" :key="`task-alert-${i}`">
|
||||||
<td v-if="t.warningDate !== null">
|
<td v-if="null !== t.warningDate">
|
||||||
{{ $d(new Date(t.warningDate.datetime), "short") }}
|
{{ $d(t.warningDate.datetime, "short") }}
|
||||||
</td>
|
</td>
|
||||||
<td v-else />
|
<td v-else />
|
||||||
<td>
|
<td>
|
||||||
<span class="outdated">{{
|
<span class="outdated">{{
|
||||||
$d(new Date(t.endDate.datetime), "short")
|
$d(t.endDate.datetime, "short")
|
||||||
}}</span>
|
}}</span>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ t.title }}</td>
|
<td>{{ t.title }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-sm btn-show" :href="getUrl(t)">
|
<a class="btn btn-sm btn-show" :href="getUrl(t)">
|
||||||
{{ trans(SHOW_ENTITY, { entity: trans(THE_TASK) }) }}
|
{{ $t("show_entity", { entity: $t("the_task") }) }}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -40,36 +40,39 @@
|
|||||||
</tab-table>
|
</tab-table>
|
||||||
|
|
||||||
<div class="alert alert-light">
|
<div class="alert alert-light">
|
||||||
{{ trans(MY_TASKS_DESCRIPTION_ALERT) }}
|
{{ $t("my_tasks.description_alert") }}
|
||||||
</div>
|
</div>
|
||||||
<span v-if="noResultsWarning" class="chill-no-data-statement">
|
<span v-if="noResultsWarning" class="chill-no-data-statement">{{
|
||||||
{{ trans(NO_DATA) }}
|
$t("no_data")
|
||||||
</span>
|
}}</span>
|
||||||
<tab-table v-else>
|
<tab-table v-else>
|
||||||
<template #thead>
|
<template #thead>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(WARNING_DATE) }}
|
{{ $t("warning_date") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(MAX_DATE) }}
|
{{ $t("max_date") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(TASK) }}
|
{{ $t("task") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" />
|
<th scope="col" />
|
||||||
</template>
|
</template>
|
||||||
<template #tbody>
|
<template #tbody>
|
||||||
<tr v-for="(t, i) in tasks.warning.results" :key="`task-warning-${i}`">
|
<tr
|
||||||
|
v-for="(t, i) in tasks.warning.results"
|
||||||
|
:key="`task-warning-${i}`"
|
||||||
|
>
|
||||||
<td>
|
<td>
|
||||||
<span class="outdated">{{
|
<span class="outdated">{{
|
||||||
$d(new Date(t.warningDate.datetime), "short")
|
$d(t.warningDate.datetime, "short")
|
||||||
}}</span>
|
}}</span>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ $d(new Date(t.endDate.datetime), "short") }}</td>
|
<td>{{ $d(t.endDate.datetime, "short") }}</td>
|
||||||
<td>{{ t.title }}</td>
|
<td>{{ t.title }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-sm btn-show" :href="getUrl(t)">
|
<a class="btn btn-sm btn-show" :href="getUrl(t)">
|
||||||
{{ trans(SHOW_ENTITY, { entity: trans(THE_TASK) }) }}
|
{{ $t("show_entity", { entity: $t("the_task") }) }}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -77,51 +80,39 @@
|
|||||||
</tab-table>
|
</tab-table>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script>
|
||||||
import { computed, ComputedRef } from "vue";
|
import { mapState, mapGetters } from "vuex";
|
||||||
import { useStore } from "vuex";
|
import TabTable from "./TabTable";
|
||||||
import TabTable from "./TabTable.vue";
|
|
||||||
import {
|
|
||||||
MY_TASKS_DESCRIPTION_ALERT,
|
|
||||||
MY_TASKS_DESCRIPTION_WARNING,
|
|
||||||
MAX_DATE,
|
|
||||||
WARNING_DATE,
|
|
||||||
TASK,
|
|
||||||
SHOW_ENTITY,
|
|
||||||
THE_TASK,
|
|
||||||
NO_DATA,
|
|
||||||
trans,
|
|
||||||
} from "translator";
|
|
||||||
import { TasksState } from "./store/modules/homepage";
|
|
||||||
import { Alert, Warning } from "ChillPersonAssets/types";
|
|
||||||
|
|
||||||
const store = useStore();
|
export default {
|
||||||
|
name: "MyTasks",
|
||||||
const tasks: ComputedRef<TasksState> = computed(
|
components: {
|
||||||
() => store.state.homepage.tasks,
|
TabTable,
|
||||||
);
|
},
|
||||||
const isTasksWarningLoaded = computed(() => store.getters.isTasksWarningLoaded);
|
computed: {
|
||||||
const isTasksAlertLoaded = computed(() => store.getters.isTasksAlertLoaded);
|
...mapState(["tasks"]),
|
||||||
|
...mapGetters(["isTasksWarningLoaded", "isTasksAlertLoaded"]),
|
||||||
const noResultsAlert = computed(() => {
|
noResultsAlert() {
|
||||||
if (!isTasksAlertLoaded.value) {
|
if (!this.isTasksAlertLoaded) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return tasks.value.alert.count === 0;
|
return this.tasks.alert.count === 0;
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
noResultsWarning() {
|
||||||
const noResultsWarning = computed(() => {
|
if (!this.isTasksWarningLoaded) {
|
||||||
if (!isTasksWarningLoaded.value) {
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return tasks.value.warning.count === 0;
|
return this.tasks.warning.count === 0;
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
},
|
||||||
function getUrl(t: Warning | Alert): string {
|
methods: {
|
||||||
|
getUrl(t) {
|
||||||
return `/fr/task/single-task/${t.id}/show`;
|
return `/fr/task/single-task/${t.id}/show`;
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@@ -1,58 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="col-12">
|
|
||||||
<!-- Loading state -->
|
|
||||||
<div
|
|
||||||
v-if="isTicketLoading"
|
|
||||||
class="d-flex justify-content-center align-items-center"
|
|
||||||
style="height: 200px"
|
|
||||||
>
|
|
||||||
<div class="text-center">
|
|
||||||
<div class="spinner-border mb-3" role="status">
|
|
||||||
<span class="visually-hidden">{{
|
|
||||||
trans(CHILL_TICKET_LIST_LOADING_TICKET)
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
<div class="text-muted">
|
|
||||||
{{ trans(CHILL_TICKET_LIST_LOADING_TICKET) }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Ticket list -->
|
|
||||||
<ticket-list-component
|
|
||||||
v-else
|
|
||||||
:tickets="ticketList"
|
|
||||||
title=""
|
|
||||||
:hasMoreTickets="pagination.next !== null"
|
|
||||||
@fetchNextPage="fetchNextPage"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { computed } from "vue";
|
|
||||||
import { useStore } from "vuex";
|
|
||||||
// Components
|
|
||||||
import TicketListComponent from "../../../../../ChillTicketBundle/src/Resources/public/vuejs/TicketList/components/TicketListComponent.vue";
|
|
||||||
|
|
||||||
// Types
|
|
||||||
import { Pagination } from "ChillMainAssets/lib/api/apiMethods";
|
|
||||||
import { TicketSimple } from "src/Bundle/ChillTicketBundle/src/Resources/public/types";
|
|
||||||
|
|
||||||
// Translation
|
|
||||||
import { CHILL_TICKET_LIST_LOADING_TICKET, trans } from "translator";
|
|
||||||
|
|
||||||
const store = useStore();
|
|
||||||
const pagination = computed(() => store.getters.getPagination as Pagination);
|
|
||||||
|
|
||||||
const ticketList = computed(
|
|
||||||
() => store.getters.getTicketList as TicketSimple[],
|
|
||||||
);
|
|
||||||
const isTicketLoading = computed(() => store.getters.isTicketLoading);
|
|
||||||
|
|
||||||
const fetchNextPage = async () => {
|
|
||||||
if (pagination.value.next) {
|
|
||||||
await store.dispatch("fetchTicketListByUrl", pagination.value.next);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
@@ -1,27 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="alert alert-light">
|
<div class="alert alert-light">
|
||||||
{{ trans(MY_WORKFLOWS_DESCRIPTION) }}
|
{{ $t("my_workflows.description") }}
|
||||||
</div>
|
</div>
|
||||||
<my-workflows-table :workflows="workflows" />
|
<my-workflows-table :workflows="workflows" />
|
||||||
|
|
||||||
<div class="alert alert-light">
|
<div class="alert alert-light">
|
||||||
{{ trans(MY_WORKFLOWS_DESCRIPTION_CC) }}
|
{{ $t("my_workflows.description_cc") }}
|
||||||
</div>
|
</div>
|
||||||
<my-workflows-table :workflows="workflowsCc" />
|
<my-workflows-table :workflows="workflowsCc" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script>
|
||||||
import { computed } from "vue";
|
import { mapState } from "vuex";
|
||||||
import { useStore } from "vuex";
|
|
||||||
import MyWorkflowsTable from "./MyWorkflowsTable.vue";
|
import MyWorkflowsTable from "./MyWorkflowsTable.vue";
|
||||||
import {
|
|
||||||
MY_WORKFLOWS_DESCRIPTION,
|
|
||||||
MY_WORKFLOWS_DESCRIPTION_CC,
|
|
||||||
trans,
|
|
||||||
} from "translator";
|
|
||||||
|
|
||||||
const store = useStore();
|
export default {
|
||||||
|
name: "MyWorkflows",
|
||||||
const workflows = computed(() => store.state.homepage.workflows);
|
components: {
|
||||||
const workflowsCc = computed(() => store.state.homepage.workflowsCc);
|
MyWorkflowsTable,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(["workflows", "workflowsCc"]),
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@@ -1,17 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<span v-if="hasNoResults" class="chill-no-data-statement">
|
<span v-if="hasNoResults(workflows)" class="chill-no-data-statement">{{
|
||||||
{{ trans(NO_DATA) }}
|
$t("no_data")
|
||||||
</span>
|
}}</span>
|
||||||
<tab-table v-else>
|
<tab-table v-else>
|
||||||
<template #thead>
|
<template #thead>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(OBJECT_WORKFLOW) }}
|
{{ $t("Object_workflow") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(STEP) }}
|
{{ $t("Step") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(CONCERNED_USERS) }}
|
{{ $t("concerned_users") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" />
|
<th scope="col" />
|
||||||
</template>
|
</template>
|
||||||
@@ -23,13 +23,15 @@
|
|||||||
<td>
|
<td>
|
||||||
<div class="workflow">
|
<div class="workflow">
|
||||||
<div class="breadcrumb">
|
<div class="breadcrumb">
|
||||||
<i class="fa fa-circle me-1 text-chill-yellow mx-2" />
|
<i
|
||||||
|
class="fa fa-circle me-1 text-chill-yellow mx-2"
|
||||||
|
/>
|
||||||
<span class="mx-2">{{ getStep(w) }}</span>
|
<span class="mx-2">{{ getStep(w) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
v-if="w.isOnHoldAtCurrentStep"
|
v-if="w.isOnHoldAtCurrentStep"
|
||||||
class="badge bg-success rounded-pill"
|
class="badge bg-success rounded-pill"
|
||||||
>{{ trans(ON_HOLD) }}</span
|
>{{ $t("on_hold") }}</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -46,7 +48,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-sm btn-show" :href="getUrl(w)">
|
<a class="btn btn-sm btn-show" :href="getUrl(w)">
|
||||||
{{ trans(SHOW_ENTITY, { entity: trans(THE_WORKFLOW) }) }}
|
{{ $t("show_entity", { entity: $t("the_workflow") }) }}
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -54,48 +56,38 @@
|
|||||||
</tab-table>
|
</tab-table>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script>
|
||||||
import { computed } from "vue";
|
import { mapGetters } from "vuex";
|
||||||
import { useStore } from "vuex";
|
import TabTable from "./TabTable";
|
||||||
import TabTable from "./TabTable.vue";
|
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly";
|
||||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
|
||||||
import { Workflow } from "ChillPersonAssets/types";
|
|
||||||
import {
|
|
||||||
CONCERNED_USERS,
|
|
||||||
OBJECT_WORKFLOW,
|
|
||||||
ON_HOLD,
|
|
||||||
SHOW_ENTITY,
|
|
||||||
THE_WORKFLOW,
|
|
||||||
NO_DATA,
|
|
||||||
STEP,
|
|
||||||
trans,
|
|
||||||
} from "translator";
|
|
||||||
import { PaginationResponse } from "ChillMainAssets/lib/api/apiMethods";
|
|
||||||
|
|
||||||
const props = defineProps<{
|
export default {
|
||||||
workflows: PaginationResponse<Workflow>;
|
name: "MyWorkflows",
|
||||||
}>();
|
components: {
|
||||||
|
TabTable,
|
||||||
const store = useStore();
|
OnTheFly,
|
||||||
|
},
|
||||||
const isWorkflowsLoaded = computed(() => store.getters.isWorkflowsLoaded);
|
props: ["workflows"],
|
||||||
|
computed: {
|
||||||
const hasNoResults = computed(() => {
|
...mapGetters(["isWorkflowsLoaded"]),
|
||||||
if (!isWorkflowsLoaded.value) {
|
},
|
||||||
|
methods: {
|
||||||
|
hasNoResults(workflows) {
|
||||||
|
if (!this.isWorkflowsLoaded) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return props.workflows.count === 0;
|
return workflows.count === 0;
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
getUrl(w) {
|
||||||
function getUrl(w: Workflow): string {
|
|
||||||
return `/fr/main/workflow/${w.id}/show`;
|
return `/fr/main/workflow/${w.id}/show`;
|
||||||
}
|
},
|
||||||
|
getStep(w) {
|
||||||
function getStep(w: Workflow): string {
|
|
||||||
const lastStep = w.steps.length - 1;
|
const lastStep = w.steps.length - 1;
|
||||||
return w.steps[lastStep].currentStep.text;
|
return w.steps[lastStep].currentStep.text;
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@@ -1,26 +1,27 @@
|
|||||||
|
// CURRENTLY NOT IN USE
|
||||||
<template>
|
<template>
|
||||||
<div class="accompanying-course-work">
|
<div class="accompanying-course-work">
|
||||||
<div class="alert alert-light">
|
<div class="alert alert-light">
|
||||||
{{ trans(MY_WORKS_DESCRIPTION) }}
|
{{ $t("my_works.description") }}
|
||||||
</div>
|
</div>
|
||||||
<span v-if="noResults" class="chill-no-data-statement">
|
<span v-if="noResults" class="chill-no-data-statement">{{
|
||||||
{{ trans(NO_DATA) }}
|
$t("no_data")
|
||||||
</span>
|
}}</span>
|
||||||
<tab-table v-else>
|
<tab-table v-else>
|
||||||
<template #thead>
|
<template #thead>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(START_DATE) }}
|
{{ $t("StartDate") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(SOCIAL_ACTION) }}
|
{{ $t("SocialAction") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
{{ trans(CONCERNED_PERSONS) }}
|
{{ $t("concerned_persons") }}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" />
|
<th scope="col" />
|
||||||
</template>
|
</template>
|
||||||
<template #tbody>
|
<template #tbody>
|
||||||
<tr v-for="(w, i) in works.value.results" :key="`works-${i}`">
|
<tr v-for="(w, i) in works.results" :key="`works-${i}`">
|
||||||
<td>{{ $d(w.startDate.datetime, "short") }}</td>
|
<td>{{ $d(w.startDate.datetime, "short") }}</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="chill-entity entity-social-issue">
|
<span class="chill-entity entity-social-issue">
|
||||||
@@ -36,7 +37,11 @@
|
|||||||
</h4>
|
</h4>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span v-for="person in w.persons" class="me-1" :key="person.id">
|
<span
|
||||||
|
v-for="person in w.persons"
|
||||||
|
class="me-1"
|
||||||
|
:key="person.id"
|
||||||
|
>
|
||||||
<on-the-fly
|
<on-the-fly
|
||||||
:type="person.type"
|
:type="person.type"
|
||||||
:id="person.id"
|
:id="person.id"
|
||||||
@@ -47,11 +52,15 @@
|
|||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group-vertical" role="group" aria-label="Actions">
|
<div
|
||||||
|
class="btn-group-vertical"
|
||||||
|
role="group"
|
||||||
|
aria-label="Actions"
|
||||||
|
>
|
||||||
<a class="btn btn-sm btn-update" :href="getUrl(w)">
|
<a class="btn btn-sm btn-update" :href="getUrl(w)">
|
||||||
{{
|
{{
|
||||||
trans(SHOW_ENTITY, {
|
$t("show_entity", {
|
||||||
entity: trans(THE_ACTION),
|
entity: $t("the_action"),
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
</a>
|
</a>
|
||||||
@@ -60,8 +69,8 @@
|
|||||||
:href="getUrl(w.accompanyingPeriod)"
|
:href="getUrl(w.accompanyingPeriod)"
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
trans(SHOW_ENTITY, {
|
$t("show_entity", {
|
||||||
entity: trans(THE_COURSE),
|
entity: $t("the_course"),
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
</a>
|
</a>
|
||||||
@@ -73,38 +82,30 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script>
|
||||||
import { computed } from "vue";
|
import { mapState, mapGetters } from "vuex";
|
||||||
import { useStore } from "vuex";
|
import TabTable from "./TabTable";
|
||||||
import TabTable from "./TabTable.vue";
|
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly";
|
||||||
import OnTheFly from "ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue";
|
|
||||||
import {
|
|
||||||
MY_WORKS_DESCRIPTION,
|
|
||||||
CONCERNED_PERSONS,
|
|
||||||
SHOW_ENTITY,
|
|
||||||
THE_COURSE,
|
|
||||||
THE_ACTION,
|
|
||||||
SOCIAL_ACTION,
|
|
||||||
START_DATE,
|
|
||||||
NO_DATA,
|
|
||||||
trans,
|
|
||||||
} from "translator";
|
|
||||||
import { Workflow } from "ChillPersonAssets/types";
|
|
||||||
|
|
||||||
const store = useStore();
|
export default {
|
||||||
|
name: "MyWorks",
|
||||||
const works = computed(() => store.state.homepage.works);
|
components: {
|
||||||
const isWorksLoaded = computed(() => store.getters.isWorksLoaded);
|
TabTable,
|
||||||
|
OnTheFly,
|
||||||
const noResults = computed(() => {
|
},
|
||||||
if (!isWorksLoaded.value) {
|
computed: {
|
||||||
|
...mapState(["works"]),
|
||||||
|
...mapGetters(["isWorksLoaded"]),
|
||||||
|
noResults() {
|
||||||
|
if (!this.isWorksLoaded) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return works.value.count === 0;
|
return this.works.count === 0;
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
},
|
||||||
function getUrl(e: Workflow): string {
|
methods: {
|
||||||
|
getUrl(e) {
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
case "accompanying_period_work":
|
case "accompanying_period_work":
|
||||||
return `/fr/person/accompanying-period/work/${e.id}/edit`;
|
return `/fr/person/accompanying-period/work/${e.id}/edit`;
|
||||||
@@ -113,7 +114,9 @@ function getUrl(e: Workflow): string {
|
|||||||
default:
|
default:
|
||||||
throw "entity type unknown";
|
throw "entity type unknown";
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
@@ -1,17 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<span v-if="isCounterAvailable" class="badge rounded-pill bg-danger mx-2">
|
<span v-if="isCounterAvailable" class="badge rounded-pill bg-danger">
|
||||||
{{ count }}
|
{{ count }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script>
|
||||||
import { computed } from "vue";
|
export default {
|
||||||
|
name: "TabCounter",
|
||||||
const props = defineProps<{
|
props: ["count"],
|
||||||
count: number;
|
computed: {
|
||||||
}>();
|
isCounterAvailable() {
|
||||||
|
return typeof this.count !== "undefined" && this.count > 0;
|
||||||
const isCounterAvailable = computed(
|
},
|
||||||
() => typeof props.count !== "undefined" && props.count > 0,
|
},
|
||||||
);
|
};
|
||||||
</script>
|
</script>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user