mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2026-01-01 06:51:23 +00:00
Compare commits
14 Commits
ticket-app
...
replace_we
| Author | SHA1 | Date | |
|---|---|---|---|
| 146d40b779 | |||
| 40cc0c2bff | |||
| 4b27454bcb | |||
| 27aa04e3fd | |||
| 441a9e018e | |||
| 0197299c89 | |||
| a30232d3ce | |||
| aae55e6f8c | |||
| c9513f2f6c | |||
| 11d7425883 | |||
| 08897e0981 | |||
| 98cbfed054 | |||
| 9af4d19744 | |||
| c1cf5a8bb2 |
@@ -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: Create invitation list in user menu
|
|
||||||
time: 2025-08-08T12:08:02.446361367+02:00
|
|
||||||
custom:
|
|
||||||
Issue: "385"
|
|
||||||
SchemaChange: No schema change
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Feature
|
|
||||||
body: Admin interface for Motive entity
|
|
||||||
time: 2025-10-07T15:59:45.597029709+02:00
|
|
||||||
custom:
|
|
||||||
Issue: ""
|
|
||||||
SchemaChange: No schema change
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Feature
|
|
||||||
body: Add an admin interface for Motive entity
|
|
||||||
time: 2025-10-22T11:15:52.13937955+02:00
|
|
||||||
custom:
|
|
||||||
Issue: ""
|
|
||||||
SchemaChange: Add columns or tables
|
|
||||||
6
.changes/unreleased/Feature-20251210-032045.yaml
Normal file
6
.changes/unreleased/Feature-20251210-032045.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Feature
|
||||||
|
body: 'Add filtering to admin lists: social actions, social issues, goals, results, and evaluations'
|
||||||
|
time: 2025-12-10T03:20:45.135973502+01:00
|
||||||
|
custom:
|
||||||
|
Issue: "478"
|
||||||
|
SchemaChange: No schema change
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
kind: Fixed
|
|
||||||
body: Fix suggestion of referrer when creating notification for accompanyingPeriodWorkDocument
|
|
||||||
time: 2025-11-06T16:16:05.861813041+01:00
|
|
||||||
custom:
|
|
||||||
Issue: "428"
|
|
||||||
SchemaChange: No schema change
|
|
||||||
7
.changes/unreleased/Fixed-20251211-214908.yaml
Normal file
7
.changes/unreleased/Fixed-20251211-214908.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: |
|
||||||
|
Fix migration query after previous fix
|
||||||
|
time: 2025-12-11T21:49:08.899926492+01:00
|
||||||
|
custom:
|
||||||
|
Issue: "466"
|
||||||
|
SchemaChange: No schema change
|
||||||
@@ -19,11 +19,11 @@ max_line_length = 80
|
|||||||
[COMMIT_EDITMSG]
|
[COMMIT_EDITMSG]
|
||||||
max_line_length = 0
|
max_line_length = 0
|
||||||
|
|
||||||
[*.{js,vue,ts}]
|
[*.{js, vue, ts}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
indent_style = space
|
indent_style = space
|
||||||
|
|
||||||
[*.rst]
|
[.rst]
|
||||||
indent_size = 3
|
ident_size = 3
|
||||||
indent_style = space
|
ident_style = space
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
13
.gitignore
vendored
13
.gitignore
vendored
@@ -50,15 +50,12 @@ phpstan.neon
|
|||||||
|
|
||||||
###> symfony/phpunit-bridge ###
|
###> symfony/phpunit-bridge ###
|
||||||
###< symfony/phpunit-bridge ###
|
###< symfony/phpunit-bridge ###
|
||||||
|
|
||||||
###> symfony/webpack-encore-bundle ###
|
|
||||||
/node_modules/
|
|
||||||
/public/build/
|
|
||||||
npm-debug.log
|
|
||||||
yarn-error.log
|
|
||||||
###< symfony/webpack-encore-bundle ###
|
|
||||||
|
|
||||||
###> friendsofphp/php-cs-fixer ###
|
###> friendsofphp/php-cs-fixer ###
|
||||||
/.php-cs-fixer.php
|
/.php-cs-fixer.php
|
||||||
/.php-cs-fixer.cache
|
/.php-cs-fixer.cache
|
||||||
###< friendsofphp/php-cs-fixer ###
|
###< friendsofphp/php-cs-fixer ###
|
||||||
|
|
||||||
|
###> pentatrion/vite-bundle ###
|
||||||
|
/node_modules/
|
||||||
|
/public/build/
|
||||||
|
###< pentatrion/vite-bundle ###
|
||||||
|
|||||||
@@ -234,17 +234,17 @@ 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).
|
||||||
|
|
||||||
Tests must be run using the `symfony` command:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Run all tests
|
||||||
|
vendor/bin/phpunit
|
||||||
|
|
||||||
# Run a specific test file
|
# Run a specific test file
|
||||||
symfony composer exec phpunit -- path/to/TestFile.php
|
vendor/bin/phpunit path/to/TestFile.php
|
||||||
|
|
||||||
# Run a specific test method
|
# Run a specific test method
|
||||||
symfony composer exec phpunit -- --filter methodName path/to/TestFile.php
|
vendor/bin/phpunit --filter methodName path/to/TestFile.php
|
||||||
```
|
```
|
||||||
|
|
||||||
When writing tests, only test specific files. Do not run all tests or the full
|
When writing tests, only test specific files. Do not run all tests or the full
|
||||||
|
|||||||
@@ -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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
import {
|
import { trans, setLocale, setLocaleFallbacks } from "./ux-translator";
|
||||||
trans,
|
|
||||||
setLocale,
|
|
||||||
getLocale,
|
|
||||||
setLocaleFallbacks,
|
|
||||||
} from "./ux-translator";
|
|
||||||
|
|
||||||
setLocaleFallbacks({ en: "fr", nl: "fr", fr: "en" });
|
setLocaleFallbacks({"en": "fr", "nl": "fr", "fr": "en"});
|
||||||
setLocale("fr");
|
setLocale('fr');
|
||||||
|
|
||||||
export { trans, getLocale };
|
export { trans };
|
||||||
export * from "../var/translations";
|
export * from '../var/translations';
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
"ocramius/package-versions": "^1.10 || ^2",
|
"ocramius/package-versions": "^1.10 || ^2",
|
||||||
"odolbeau/phone-number-bundle": "^3.6",
|
"odolbeau/phone-number-bundle": "^3.6",
|
||||||
"ovh/ovh": "^3.0",
|
"ovh/ovh": "^3.0",
|
||||||
|
"pentatrion/vite-bundle": "^8.2",
|
||||||
"phpoffice/phpspreadsheet": "^1.16",
|
"phpoffice/phpspreadsheet": "^1.16",
|
||||||
"ramsey/uuid-doctrine": "^1.7",
|
"ramsey/uuid-doctrine": "^1.7",
|
||||||
"sensio/framework-extra-bundle": "^5.5",
|
"sensio/framework-extra-bundle": "^5.5",
|
||||||
@@ -84,7 +85,6 @@
|
|||||||
"symfony/twig-bundle": "^5.4",
|
"symfony/twig-bundle": "^5.4",
|
||||||
"symfony/ux-translator": "^2.22",
|
"symfony/ux-translator": "^2.22",
|
||||||
"symfony/validator": "^5.4",
|
"symfony/validator": "^5.4",
|
||||||
"symfony/webpack-encore-bundle": "^1.11",
|
|
||||||
"symfony/workflow": "^5.4",
|
"symfony/workflow": "^5.4",
|
||||||
"symfony/yaml": "^5.4",
|
"symfony/yaml": "^5.4",
|
||||||
"thenetworg/oauth2-azure": "^2.0",
|
"thenetworg/oauth2-azure": "^2.0",
|
||||||
@@ -141,7 +141,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"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ return [
|
|||||||
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
|
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
|
||||||
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||||
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
||||||
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
|
|
||||||
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
|
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
|
||||||
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
|
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
|
||||||
Chill\ActivityBundle\ChillActivityBundle::class => ['all' => true],
|
Chill\ActivityBundle\ChillActivityBundle::class => ['all' => true],
|
||||||
@@ -34,8 +33,8 @@ return [
|
|||||||
Chill\ThirdPartyBundle\ChillThirdPartyBundle::class => ['all' => true],
|
Chill\ThirdPartyBundle\ChillThirdPartyBundle::class => ['all' => true],
|
||||||
Chill\BudgetBundle\ChillBudgetBundle::class => ['all' => true],
|
Chill\BudgetBundle\ChillBudgetBundle::class => ['all' => true],
|
||||||
Chill\WopiBundle\ChillWopiBundle::class => ['all' => true],
|
Chill\WopiBundle\ChillWopiBundle::class => ['all' => true],
|
||||||
Chill\TicketBundle\ChillTicketBundle::class => ['all' => true],
|
|
||||||
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
|
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
|
||||||
Symfony\UX\Translator\UxTranslatorBundle::class => ['all' => true],
|
Symfony\UX\Translator\UxTranslatorBundle::class => ['all' => true],
|
||||||
loophp\PsrHttpMessageBridgeBundle\PsrHttpMessageBridgeBundle::class => ['all' => true],
|
loophp\PsrHttpMessageBridgeBundle\PsrHttpMessageBridgeBundle::class => ['all' => true],
|
||||||
|
Pentatrion\ViteBundle\PentatrionViteBundle::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,6 +1,8 @@
|
|||||||
framework:
|
framework:
|
||||||
assets:
|
assets:
|
||||||
json_manifest_path: '%kernel.project_dir%/public/build/manifest.json'
|
# Disable Encore-style manifest for default assets package. Vite (Pentatrion) uses public/build/.vite/manifest.json
|
||||||
|
# internally for vite_entry_* helpers; Symfony's asset() should not depend on a manifest.
|
||||||
|
json_manifest_path: null
|
||||||
|
|
||||||
when@test:
|
when@test:
|
||||||
framework:
|
framework:
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ framework:
|
|||||||
'Chill\MainBundle\Export\Messenger\ExportRequestGenerationMessage': priority
|
'Chill\MainBundle\Export\Messenger\ExportRequestGenerationMessage': priority
|
||||||
'Chill\MainBundle\Export\Messenger\RemoveExportGenerationMessage': async
|
'Chill\MainBundle\Export\Messenger\RemoveExportGenerationMessage': async
|
||||||
'Chill\MainBundle\Notification\Email\NotificationEmailMessages\ScheduleDailyNotificationDigestMessage': async
|
'Chill\MainBundle\Notification\Email\NotificationEmailMessages\ScheduleDailyNotificationDigestMessage': async
|
||||||
'Chill\TicketBundle\Messenger\PostTicketUpdateMessage': async
|
|
||||||
# end of routes added by chill-bundles recipes
|
# end of routes added by chill-bundles recipes
|
||||||
# Route your messages to the transports
|
# Route your messages to the transports
|
||||||
# 'App\Message\YourMessage': async
|
# 'App\Message\YourMessage': async
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
webpack_encore:
|
|
||||||
# The path where Encore is building the assets - i.e. Encore.setOutputPath()
|
|
||||||
output_path: '%kernel.project_dir%/public/build'
|
|
||||||
# If multiple builds are defined (as shown below), you can disable the default build:
|
|
||||||
# output_path: false
|
|
||||||
|
|
||||||
# Set attributes that will be rendered on all script and link tags
|
|
||||||
script_attributes:
|
|
||||||
defer: true
|
|
||||||
# Uncomment (also under link_attributes) if using Turbo Drive
|
|
||||||
# https://turbo.hotwired.dev/handbook/drive#reloading-when-assets-change
|
|
||||||
# 'data-turbo-track': reload
|
|
||||||
# link_attributes:
|
|
||||||
# Uncomment if using Turbo Drive
|
|
||||||
# 'data-turbo-track': reload
|
|
||||||
|
|
||||||
# If using Encore.enableIntegrityHashes() and need the crossorigin attribute (default: false, or use 'anonymous' or 'use-credentials')
|
|
||||||
# crossorigin: 'anonymous'
|
|
||||||
|
|
||||||
# Preload all rendered script and link tags automatically via the HTTP/2 Link header
|
|
||||||
# preload: true
|
|
||||||
|
|
||||||
# Throw an exception if the entrypoints.json file is missing or an entry is missing from the data
|
|
||||||
# strict_mode: false
|
|
||||||
|
|
||||||
# If you have multiple builds:
|
|
||||||
# builds:
|
|
||||||
# frontend: '%kernel.project_dir%/public/frontend/build'
|
|
||||||
|
|
||||||
# pass the build name as the 3rd argument to the Twig functions
|
|
||||||
# {{ encore_entry_script_tags('entry1', null, 'frontend') }}
|
|
||||||
|
|
||||||
#when@prod:
|
|
||||||
# webpack_encore:
|
|
||||||
# # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes)
|
|
||||||
# # Available in version 1.2
|
|
||||||
# cache: true
|
|
||||||
|
|
||||||
when@test:
|
|
||||||
webpack_encore:
|
|
||||||
strict_mode: false
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
chill_ticket_bundle:
|
|
||||||
resource: '@ChillTicketBundle/config/routes.yaml'
|
|
||||||
9
config/routes/pentatrion_vite.yaml
Normal file
9
config/routes/pentatrion_vite.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
when@dev:
|
||||||
|
_pentatrion_vite:
|
||||||
|
prefix: /build
|
||||||
|
resource: "@PentatrionViteBundle/Resources/config/routing.yaml"
|
||||||
|
|
||||||
|
_profiler_vite:
|
||||||
|
path: /_profiler/vite
|
||||||
|
defaults:
|
||||||
|
_controller: Pentatrion\ViteBundle\Controller\ProfilerController::info
|
||||||
@@ -1,90 +1,23 @@
|
|||||||
# Create a new bundle {#create-new-bundle}
|
Permission is granted to copy, distribute and/or modify this document
|
||||||
|
under the terms of the GNU Free Documentation License, Version 1.3
|
||||||
|
or any later version published by the Free Software Foundation;
|
||||||
|
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
|
||||||
|
A copy of the license is included in the section entitled "GNU
|
||||||
|
Free Documentation License".
|
||||||
|
|
||||||
:::: warning
|
###### Create a new bundle
|
||||||
::: title
|
|
||||||
Warning
|
|
||||||
:::
|
|
||||||
|
|
||||||
This part of the doc is not yet tested
|
Create your own bundle is not a trivial task.
|
||||||
::::
|
|
||||||
|
|
||||||
## Create a new directory with Bundle class
|
The easiest way to achieve this is seems to be :
|
||||||
|
|
||||||
``` bash
|
1. Prepare a fresh installation of the chill project, in a new directory
|
||||||
mkdir -p src/Bundle/ChillSomeBundle/src/config
|
2. Create a new bundle in this project, in the src directory
|
||||||
mkdir -p src/Bundle/ChillSomeBundle/src/Controller
|
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 [installation-for-development` section, and add your new repository to the composer.json file
|
||||||
|
6. Work as :ref:`usual ](editing-code-and-commiting.md)
|
||||||
|
|
||||||
Add a bundle file
|
This part of the doc is not yet tested
|
||||||
|
|
||||||
``` php
|
TODO
|
||||||
<?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:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
chill_ticket_controller:
|
|
||||||
resource: '@ChillTicketBundle/Controller/'
|
|
||||||
type: annotation
|
|
||||||
```
|
|
||||||
|
|
||||||
## Register the new psr-4 namespace
|
|
||||||
|
|
||||||
In composer.json, add the new psr4 namespace
|
|
||||||
|
|
||||||
``` diff
|
|
||||||
{
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
+ "Chill\\SomeBundle\\": "src/Bundle/ChillSomeBundle/src",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Register the bundle
|
|
||||||
|
|
||||||
Register in the file `config/bundles.php`:
|
|
||||||
|
|
||||||
``` php
|
|
||||||
Vendor\Bundle\YourBundle\YourBundle::class => ['all' => true],
|
|
||||||
```
|
|
||||||
|
|
||||||
And import routes in `config/routes/chill_some_bundle.yaml`:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
chill_ticket_bundle:
|
|
||||||
resource: '@ChillSomeBundle/config/routes.yaml'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Add the doctrine_migration namespace
|
|
||||||
|
|
||||||
Add the namespace to `config/packages/doctrine_migrations_chill.yaml`
|
|
||||||
|
|
||||||
``` diff
|
|
||||||
doctrine_migrations:
|
|
||||||
migrations_paths:
|
|
||||||
+ 'Chill\Some\Ticket': '@ChillSomeBundle/migrations'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Dump autoloading
|
|
||||||
|
|
||||||
``` bash
|
|
||||||
symfony composer dump-autoload
|
|
||||||
```
|
|
||||||
38
package.json
38
package.json
@@ -1,6 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "chill",
|
"name": "chill-bundles",
|
||||||
|
"private": true,
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
"description": "Chill web application frontend (Vite build at repo root)",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"eslint": "eslint . --ext .js,.ts,.vue"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@alexlafroscia/yaml-merge": "^4.0.0",
|
"@alexlafroscia/yaml-merge": "^4.0.0",
|
||||||
"@apidevtools/swagger-cli": "^4.0.4",
|
"@apidevtools/swagger-cli": "^4.0.4",
|
||||||
@@ -11,11 +20,11 @@
|
|||||||
"@hotwired/stimulus": "^3.0.0",
|
"@hotwired/stimulus": "^3.0.0",
|
||||||
"@luminateone/eslint-baseline": "^1.0.9",
|
"@luminateone/eslint-baseline": "^1.0.9",
|
||||||
"@symfony/stimulus-bridge": "^3.2.0",
|
"@symfony/stimulus-bridge": "^3.2.0",
|
||||||
"@symfony/webpack-encore": "^4.1.0",
|
|
||||||
"@tsconfig/node20": "^20.1.4",
|
"@tsconfig/node20": "^20.1.4",
|
||||||
"@types/dompurify": "^3.0.5",
|
"@types/dompurify": "^3.0.5",
|
||||||
"@types/eslint__js": "^8.42.3",
|
"@types/eslint__js": "^8.42.3",
|
||||||
"@typescript-eslint/parser": "^8.12.2",
|
"@typescript-eslint/parser": "^8.12.2",
|
||||||
|
"@vitejs/plugin-vue": "^5.1.4",
|
||||||
"bindings": "^1.5.0",
|
"bindings": "^1.5.0",
|
||||||
"bootstrap": "^5.3.6",
|
"bootstrap": "^5.3.6",
|
||||||
"chokidar": "^3.5.1",
|
"chokidar": "^3.5.1",
|
||||||
@@ -40,10 +49,9 @@
|
|||||||
"ts-loader": "^9.3.1",
|
"ts-loader": "^9.3.1",
|
||||||
"typescript": "^5.6.3",
|
"typescript": "^5.6.3",
|
||||||
"typescript-eslint": "^8.13.0",
|
"typescript-eslint": "^8.13.0",
|
||||||
"vue-loader": "^17.0.0",
|
"vite": "^5.4.8",
|
||||||
"vue-tsc": "^3.1.3",
|
"vite-plugin-symfony": "^8",
|
||||||
"webpack": "^5.75.0",
|
"vue-loader": "^17.0.0"
|
||||||
"webpack-cli": "^5.0.1"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fullcalendar/core": "^6.1.4",
|
"@fullcalendar/core": "^6.1.4",
|
||||||
@@ -72,21 +80,5 @@
|
|||||||
"vue-multiselect": "3.0.0-alpha.2",
|
"vue-multiselect": "3.0.0-alpha.2",
|
||||||
"vue-toast-notification": "^3.1.2",
|
"vue-toast-notification": "^3.1.2",
|
||||||
"vuex": "^4.0.0"
|
"vuex": "^4.0.0"
|
||||||
},
|
}
|
||||||
"browserslist": [
|
|
||||||
"defaults and fully supports es6-module and not dead"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"dev-server": "encore dev-server",
|
|
||||||
"dev": "encore dev",
|
|
||||||
"watch": "encore dev --watch",
|
|
||||||
"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-validate": "swagger-cli validate templates/api/specs.yaml",
|
|
||||||
"specs-create-dir": "mkdir -p templates/api",
|
|
||||||
"specs": "yarn run specs-create-dir && yarn run specs-build && yarn run specs-validate",
|
|
||||||
"version": "node --version",
|
|
||||||
"eslint": "eslint-baseline --fix \"src/**/*.{js,ts,vue}\""
|
|
||||||
},
|
|
||||||
"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>
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
In this directory, you find an example of file for the command `chill:main:ticket_motives_import`.
|
|
||||||
|
|
||||||
This file contains a list of ticket motives to import into the system. Each entry is a dictionary with two keys: `code` and `label`. The `code` key contains the unique code for the ticket motive, and the `label` key contains the human-readable label for the ticket motive.
|
|
||||||
|
|
||||||
The `stored_objects` key contains the documents that will be associated with the tickets. They must be found in the same directory.
|
|
||||||
|
|
||||||
The command `chill:main:ticket_motives_import` uses this file to import the specified ticket motives into the system.
|
|
||||||
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
- label:
|
|
||||||
fr: Appel famille pour annonce de décès
|
|
||||||
urgent: false
|
|
||||||
supplementary_informations:
|
|
||||||
- label:
|
|
||||||
fr: Date du décès
|
|
||||||
- label:
|
|
||||||
fr: lieu du décès (domicile ou hôpital)
|
|
||||||
- label:
|
|
||||||
fr: nom de l’hôpital
|
|
||||||
- label:
|
|
||||||
fr: service concerné
|
|
||||||
stored_objects:
|
|
||||||
- label:
|
|
||||||
fr: ☀️ De 07h à 21h
|
|
||||||
filename: 2_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 🌙 De 21h à 07h du matin
|
|
||||||
filename: 3_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 🗓️ Dimanches et jours fériés
|
|
||||||
filename: 4_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 'Appel famille pour annonce absence : hospitalisation ou consultation'
|
|
||||||
urgent: false
|
|
||||||
supplementary_informations:
|
|
||||||
- label:
|
|
||||||
fr: Quel hôpital
|
|
||||||
- label:
|
|
||||||
fr: quel service
|
|
||||||
- label:
|
|
||||||
fr: pour quelles raisons
|
|
||||||
- label:
|
|
||||||
fr: 'consultation : date et heure'
|
|
||||||
- label:
|
|
||||||
fr: hospitalisation complète ou HDJ
|
|
||||||
stored_objects:
|
|
||||||
- label:
|
|
||||||
fr: ☀️ De 07h à 21h
|
|
||||||
filename: 5_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 🌙 De 21h à 07h du matin
|
|
||||||
filename: 6_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 🗓️ Dimanches et jours fériés
|
|
||||||
filename: 7_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 'Appel famille pour annonce absence : interruption de prise en charge'
|
|
||||||
urgent: false
|
|
||||||
supplementary_informations:
|
|
||||||
- label:
|
|
||||||
fr: Pour quelles raisons ? Date
|
|
||||||
- label:
|
|
||||||
fr: durée
|
|
||||||
- label:
|
|
||||||
fr: accord médical ?
|
|
||||||
stored_objects:
|
|
||||||
- label:
|
|
||||||
fr: ☀️ De 07h à 21h
|
|
||||||
filename: 8_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 🌙 De 21h à 07h du matin
|
|
||||||
filename: 9_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 🗓️ Dimanches et jours fériés
|
|
||||||
filename: 10_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 'Appel famille pour annonce absence : changement d’adresse'
|
|
||||||
urgent: false
|
|
||||||
supplementary_informations:
|
|
||||||
- label:
|
|
||||||
fr: Où
|
|
||||||
- label:
|
|
||||||
fr: Pourquoi ? Pour combien de temps ? Besoin d’un relais des soins ? Nouvelle adresse ?
|
|
||||||
stored_objects:
|
|
||||||
- label:
|
|
||||||
fr: ☀️ De 07h à 21h
|
|
||||||
filename: 11_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 🌙 De 21h à 07h du matin
|
|
||||||
filename: 12_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 🗓️ Dimanches et jours fériés
|
|
||||||
filename: 13_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: Appel famille pour altération de l’état général du patient
|
|
||||||
urgent: true
|
|
||||||
supplementary_informations:
|
|
||||||
- label:
|
|
||||||
fr: Recherche des symptômes
|
|
||||||
- label:
|
|
||||||
fr: Attentes par rapport à la demande
|
|
||||||
stored_objects:
|
|
||||||
- label:
|
|
||||||
fr: ☀️ De 07h à 21h
|
|
||||||
filename: 14_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 🌙 De 21h à 07h du matin
|
|
||||||
filename: 15_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 🗓️ Dimanches et jours fériés
|
|
||||||
filename: 16_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: Appel famille pour prise en charge de la douleur
|
|
||||||
urgent: true
|
|
||||||
supplementary_informations:
|
|
||||||
- label:
|
|
||||||
fr: Localisation douleur
|
|
||||||
- label:
|
|
||||||
fr: Horaire dernier passage
|
|
||||||
- label:
|
|
||||||
fr: Traitements en cours
|
|
||||||
stored_objects:
|
|
||||||
- label:
|
|
||||||
fr: ☀️ De 07h à 21h
|
|
||||||
filename: 17_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 🌙 De 21h à 07h du matin
|
|
||||||
filename: 18_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 🗓️ Dimanches et jours fériés
|
|
||||||
filename: 19_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: Appel famille pour information sur la date de prise en charge
|
|
||||||
urgent: false
|
|
||||||
supplementary_informations: []
|
|
||||||
stored_objects:
|
|
||||||
- label:
|
|
||||||
fr: ☀️ De 07h à 21h
|
|
||||||
filename: 20_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 🌙 De 21h à 07h du matin
|
|
||||||
filename: 21_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
- label:
|
|
||||||
fr: 🗓️ Dimanches et jours fériés
|
|
||||||
filename: 22_doc_20250402_Pelotons flux externes consolidés.pdf
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
In this directory, you find an example of file for the command `chill:main:override_translation`.
|
|
||||||
|
|
||||||
This file contains a list of translations to override in the translation catalogue. Each entry is a dictionary with two keys: `from` and `to`. The `from` key contains the original translation string, and the `to` key contains the replacement string.
|
|
||||||
|
|
||||||
The command `chill:main:override_translation` uses this file to generate a new translation catalogue with the specified overrides applied.
|
|
||||||
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
- {from: "de l'usager", to: "du patient"}
|
|
||||||
- {from: "l'usager", to: "le patient"}
|
|
||||||
- {from: "L'usager", to: "Le patient"}
|
|
||||||
- {from: "d'usagers", to: "de patients"}
|
|
||||||
- {from: "usagers", to: "patients"}
|
|
||||||
- {from: "Usagers", to: "Patients"}
|
|
||||||
- {from: "usager", to: "patient"}
|
|
||||||
- {from: "Usager", to: "Patient"}
|
|
||||||
@@ -1 +1 @@
|
|||||||
require("./chillactivity.scss");
|
import "./chillactivity.scss";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<concerned-groups v-if="hasPerson" />
|
<concerned-groups v-if="hasPerson" />
|
||||||
<social-issues-acc v-if="hasSocialIssues" />
|
<social-issues-acc v-if="hasSocialIssues" />
|
||||||
<location v-if="hasLocation" />
|
<location v-if="hasLocation" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -10,12 +10,12 @@ import SocialIssuesAcc from "./components/SocialIssuesAcc.vue";
|
|||||||
import Location from "./components/Location.vue";
|
import Location from "./components/Location.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
props: ["hasSocialIssues", "hasLocation", "hasPerson"],
|
props: ["hasSocialIssues", "hasLocation", "hasPerson"],
|
||||||
components: {
|
components: {
|
||||||
ConcernedGroups,
|
ConcernedGroups,
|
||||||
SocialIssuesAcc,
|
SocialIssuesAcc,
|
||||||
Location,
|
Location,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,43 +1,46 @@
|
|||||||
<template>
|
<template>
|
||||||
<teleport to="#add-persons" v-if="isComponentVisible">
|
<teleport to="#add-persons" v-if="isComponentVisible">
|
||||||
<div class="flex-bloc concerned-groups" :class="getContext">
|
<div class="flex-bloc concerned-groups" :class="getContext">
|
||||||
<persons-bloc
|
<persons-bloc
|
||||||
v-for="bloc in contextPersonsBlocs"
|
v-for="bloc in contextPersonsBlocs"
|
||||||
:key="bloc.key"
|
:key="bloc.key"
|
||||||
:bloc="bloc"
|
:bloc="bloc"
|
||||||
:bloc-width="getBlocWidth"
|
:bloc-width="getBlocWidth"
|
||||||
:set-persons-in-bloc="setPersonsInBloc"
|
:set-persons-in-bloc="setPersonsInBloc"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="getContext === 'accompanyingCourse' && suggestedEntities.length > 0"
|
v-if="
|
||||||
>
|
getContext === 'accompanyingCourse' &&
|
||||||
<ul class="list-suggest add-items inline">
|
suggestedEntities.length > 0
|
||||||
<li
|
"
|
||||||
v-for="(p, i) in suggestedEntities"
|
|
||||||
@click="addSuggestedEntity(p)"
|
|
||||||
:key="`suggestedEntities-${i}`"
|
|
||||||
>
|
>
|
||||||
<person-text v-if="p.type === 'person'" :person="p" />
|
<ul class="list-suggest add-items inline">
|
||||||
<span v-else>{{ p.text }}</span>
|
<li
|
||||||
</li>
|
v-for="(p, i) in suggestedEntities"
|
||||||
</ul>
|
@click="addSuggestedEntity(p)"
|
||||||
</div>
|
:key="`suggestedEntities-${i}`"
|
||||||
|
>
|
||||||
|
<person-text v-if="p.type === 'person'" :person="p" />
|
||||||
|
<span v-else>{{ p.text }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li class="add-persons">
|
<li class="add-persons">
|
||||||
<add-persons
|
<add-persons
|
||||||
:buttonTitle="trans(ACTIVITY_ADD_PERSONS)"
|
:buttonTitle="trans(ACTIVITY_ADD_PERSONS)"
|
||||||
:modalTitle="trans(ACTIVITY_ADD_PERSONS)"
|
:modalTitle="trans(ACTIVITY_ADD_PERSONS)"
|
||||||
v-bind:key="addPersons.key"
|
v-bind:key="addPersons.key"
|
||||||
v-bind:options="addPersonsOptions"
|
v-bind:options="addPersonsOptions"
|
||||||
@addNewPersons="addNewPersons"
|
@addNewPersons="addNewPersons"
|
||||||
ref="addPersons"
|
ref="addPersons"
|
||||||
>
|
>
|
||||||
</add-persons>
|
</add-persons>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</teleport>
|
</teleport>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -46,208 +49,208 @@ import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
|
|||||||
import PersonsBloc from "./ConcernedGroups/PersonsBloc.vue";
|
import PersonsBloc from "./ConcernedGroups/PersonsBloc.vue";
|
||||||
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
|
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
|
||||||
import {
|
import {
|
||||||
ACTIVITY_BLOC_PERSONS,
|
ACTIVITY_BLOC_PERSONS,
|
||||||
ACTIVITY_BLOC_PERSONS_ASSOCIATED,
|
ACTIVITY_BLOC_PERSONS_ASSOCIATED,
|
||||||
ACTIVITY_BLOC_THIRDPARTY,
|
ACTIVITY_BLOC_THIRDPARTY,
|
||||||
ACTIVITY_BLOC_USERS,
|
ACTIVITY_BLOC_USERS,
|
||||||
ACTIVITY_ADD_PERSONS,
|
ACTIVITY_ADD_PERSONS,
|
||||||
trans,
|
trans,
|
||||||
} from "translator";
|
} from "translator";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ConcernedGroups",
|
name: "ConcernedGroups",
|
||||||
components: {
|
components: {
|
||||||
AddPersons,
|
AddPersons,
|
||||||
PersonsBloc,
|
PersonsBloc,
|
||||||
PersonText,
|
PersonText,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
return {
|
return {
|
||||||
trans,
|
trans,
|
||||||
ACTIVITY_ADD_PERSONS,
|
ACTIVITY_ADD_PERSONS,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
personsBlocs: [
|
personsBlocs: [
|
||||||
{
|
{
|
||||||
key: "persons",
|
key: "persons",
|
||||||
title: trans(ACTIVITY_BLOC_PERSONS),
|
title: trans(ACTIVITY_BLOC_PERSONS),
|
||||||
persons: [],
|
persons: [],
|
||||||
included: false,
|
included: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "personsAssociated",
|
||||||
|
title: trans(ACTIVITY_BLOC_PERSONS_ASSOCIATED),
|
||||||
|
persons: [],
|
||||||
|
included: window.activity
|
||||||
|
? window.activity.activityType.personsVisible !== 0
|
||||||
|
: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "personsNotAssociated",
|
||||||
|
title: "activity.bloc_persons_not_associated",
|
||||||
|
persons: [],
|
||||||
|
included: window.activity
|
||||||
|
? window.activity.activityType.personsVisible !== 0
|
||||||
|
: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "thirdparty",
|
||||||
|
title: trans(ACTIVITY_BLOC_THIRDPARTY),
|
||||||
|
persons: [],
|
||||||
|
included: window.activity
|
||||||
|
? window.activity.activityType.thirdPartiesVisible !== 0
|
||||||
|
: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "users",
|
||||||
|
title: trans(ACTIVITY_BLOC_USERS),
|
||||||
|
persons: [],
|
||||||
|
included: window.activity
|
||||||
|
? window.activity.activityType.usersVisible !== 0
|
||||||
|
: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
addPersons: {
|
||||||
|
key: "activity",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isComponentVisible() {
|
||||||
|
return window.activity
|
||||||
|
? window.activity.activityType.personsVisible !== 0 ||
|
||||||
|
window.activity.activityType.thirdPartiesVisible !== 0 ||
|
||||||
|
window.activity.activityType.usersVisible !== 0
|
||||||
|
: true;
|
||||||
},
|
},
|
||||||
{
|
...mapState({
|
||||||
key: "personsAssociated",
|
persons: (state) => state.activity.persons,
|
||||||
title: trans(ACTIVITY_BLOC_PERSONS_ASSOCIATED),
|
thirdParties: (state) => state.activity.thirdParties,
|
||||||
persons: [],
|
users: (state) => state.activity.users,
|
||||||
included: window.activity
|
accompanyingCourse: (state) => state.activity.accompanyingPeriod,
|
||||||
? window.activity.activityType.personsVisible !== 0
|
}),
|
||||||
: true,
|
...mapGetters(["suggestedEntities"]),
|
||||||
|
getContext() {
|
||||||
|
return this.accompanyingCourse ? "accompanyingCourse" : "person";
|
||||||
},
|
},
|
||||||
{
|
contextPersonsBlocs() {
|
||||||
key: "personsNotAssociated",
|
return this.personsBlocs.filter((bloc) => bloc.included !== false);
|
||||||
title: "activity.bloc_persons_not_associated",
|
|
||||||
persons: [],
|
|
||||||
included: window.activity
|
|
||||||
? window.activity.activityType.personsVisible !== 0
|
|
||||||
: true,
|
|
||||||
},
|
},
|
||||||
{
|
addPersonsOptions() {
|
||||||
key: "thirdparty",
|
let optionsType = [];
|
||||||
title: trans(ACTIVITY_BLOC_THIRDPARTY),
|
if (window.activity) {
|
||||||
persons: [],
|
if (window.activity.activityType.personsVisible !== 0) {
|
||||||
included: window.activity
|
optionsType.push("person");
|
||||||
? window.activity.activityType.thirdPartiesVisible !== 0
|
}
|
||||||
: true,
|
if (window.activity.activityType.thirdPartiesVisible !== 0) {
|
||||||
|
optionsType.push("thirdparty");
|
||||||
|
}
|
||||||
|
if (window.activity.activityType.usersVisible !== 0) {
|
||||||
|
optionsType.push("user");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
optionsType = ["person", "thirdparty", "user"];
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: optionsType,
|
||||||
|
priority: null,
|
||||||
|
uniq: false,
|
||||||
|
button: {
|
||||||
|
size: "btn-sm",
|
||||||
|
},
|
||||||
|
};
|
||||||
},
|
},
|
||||||
{
|
getBlocWidth() {
|
||||||
key: "users",
|
return Math.round(100 / this.contextPersonsBlocs.length) + "%";
|
||||||
title: trans(ACTIVITY_BLOC_USERS),
|
|
||||||
persons: [],
|
|
||||||
included: window.activity
|
|
||||||
? window.activity.activityType.usersVisible !== 0
|
|
||||||
: true,
|
|
||||||
},
|
},
|
||||||
],
|
|
||||||
addPersons: {
|
|
||||||
key: "activity",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
isComponentVisible() {
|
|
||||||
return window.activity
|
|
||||||
? window.activity.activityType.personsVisible !== 0 ||
|
|
||||||
window.activity.activityType.thirdPartiesVisible !== 0 ||
|
|
||||||
window.activity.activityType.usersVisible !== 0
|
|
||||||
: true;
|
|
||||||
},
|
},
|
||||||
...mapState({
|
mounted() {
|
||||||
persons: (state) => state.activity.persons,
|
this.setPersonsInBloc();
|
||||||
thirdParties: (state) => state.activity.thirdParties,
|
|
||||||
users: (state) => state.activity.users,
|
|
||||||
accompanyingCourse: (state) => state.activity.accompanyingPeriod,
|
|
||||||
}),
|
|
||||||
...mapGetters(["suggestedEntities"]),
|
|
||||||
getContext() {
|
|
||||||
return this.accompanyingCourse ? "accompanyingCourse" : "person";
|
|
||||||
},
|
},
|
||||||
contextPersonsBlocs() {
|
methods: {
|
||||||
return this.personsBlocs.filter((bloc) => bloc.included !== false);
|
setPersonsInBloc() {
|
||||||
},
|
let groups;
|
||||||
addPersonsOptions() {
|
if (this.accompanyingCourse) {
|
||||||
let optionsType = [];
|
groups = this.splitPersonsInGroups();
|
||||||
if (window.activity) {
|
}
|
||||||
if (window.activity.activityType.personsVisible !== 0) {
|
this.personsBlocs.forEach((bloc) => {
|
||||||
optionsType.push("person");
|
if (this.accompanyingCourse) {
|
||||||
}
|
switch (bloc.key) {
|
||||||
if (window.activity.activityType.thirdPartiesVisible !== 0) {
|
case "personsAssociated":
|
||||||
optionsType.push("thirdparty");
|
bloc.persons = groups.personsAssociated;
|
||||||
}
|
bloc.included = true;
|
||||||
if (window.activity.activityType.usersVisible !== 0) {
|
break;
|
||||||
optionsType.push("user");
|
case "personsNotAssociated":
|
||||||
}
|
bloc.persons = groups.personsNotAssociated;
|
||||||
} else {
|
bloc.included = true;
|
||||||
optionsType = ["person", "thirdparty", "user"];
|
break;
|
||||||
}
|
}
|
||||||
return {
|
} else {
|
||||||
type: optionsType,
|
switch (bloc.key) {
|
||||||
priority: null,
|
case "persons":
|
||||||
uniq: false,
|
bloc.persons = this.persons;
|
||||||
button: {
|
bloc.included = true;
|
||||||
size: "btn-sm",
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (bloc.key) {
|
||||||
|
case "thirdparty":
|
||||||
|
bloc.persons = this.thirdParties;
|
||||||
|
break;
|
||||||
|
case "users":
|
||||||
|
bloc.persons = this.users;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}, groups);
|
||||||
|
},
|
||||||
|
splitPersonsInGroups() {
|
||||||
|
let personsAssociated = [];
|
||||||
|
let personsNotAssociated = this.persons;
|
||||||
|
let participations = this.getCourseParticipations();
|
||||||
|
this.persons.forEach((person) => {
|
||||||
|
participations.forEach((participation) => {
|
||||||
|
if (person.id === participation.id) {
|
||||||
|
//console.log(person.id);
|
||||||
|
personsAssociated.push(person);
|
||||||
|
personsNotAssociated = personsNotAssociated.filter(
|
||||||
|
(p) => p !== person,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
personsAssociated: personsAssociated,
|
||||||
|
personsNotAssociated: personsNotAssociated,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
getCourseParticipations() {
|
||||||
|
let participations = [];
|
||||||
|
this.accompanyingCourse.participations.forEach((participation) => {
|
||||||
|
if (!participation.endDate) {
|
||||||
|
participations.push(participation.person);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return participations;
|
||||||
|
},
|
||||||
|
addNewPersons({ selected, modal }) {
|
||||||
|
console.log("@@@ CLICK button addNewPersons", selected);
|
||||||
|
selected.forEach((item) => {
|
||||||
|
this.$store.dispatch("addPersonsInvolved", item);
|
||||||
|
}, this);
|
||||||
|
this.$refs.addPersons.resetSearch(); // to cast child method
|
||||||
|
modal.showModal = false;
|
||||||
|
this.setPersonsInBloc();
|
||||||
|
},
|
||||||
|
addSuggestedEntity(person) {
|
||||||
|
this.$store.dispatch("addPersonsInvolved", {
|
||||||
|
result: person,
|
||||||
|
type: "person",
|
||||||
|
});
|
||||||
|
this.setPersonsInBloc();
|
||||||
},
|
},
|
||||||
};
|
|
||||||
},
|
},
|
||||||
getBlocWidth() {
|
|
||||||
return Math.round(100 / this.contextPersonsBlocs.length) + "%";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.setPersonsInBloc();
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
setPersonsInBloc() {
|
|
||||||
let groups;
|
|
||||||
if (this.accompanyingCourse) {
|
|
||||||
groups = this.splitPersonsInGroups();
|
|
||||||
}
|
|
||||||
this.personsBlocs.forEach((bloc) => {
|
|
||||||
if (this.accompanyingCourse) {
|
|
||||||
switch (bloc.key) {
|
|
||||||
case "personsAssociated":
|
|
||||||
bloc.persons = groups.personsAssociated;
|
|
||||||
bloc.included = true;
|
|
||||||
break;
|
|
||||||
case "personsNotAssociated":
|
|
||||||
bloc.persons = groups.personsNotAssociated;
|
|
||||||
bloc.included = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (bloc.key) {
|
|
||||||
case "persons":
|
|
||||||
bloc.persons = this.persons;
|
|
||||||
bloc.included = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (bloc.key) {
|
|
||||||
case "thirdparty":
|
|
||||||
bloc.persons = this.thirdParties;
|
|
||||||
break;
|
|
||||||
case "users":
|
|
||||||
bloc.persons = this.users;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}, groups);
|
|
||||||
},
|
|
||||||
splitPersonsInGroups() {
|
|
||||||
let personsAssociated = [];
|
|
||||||
let personsNotAssociated = this.persons;
|
|
||||||
let participations = this.getCourseParticipations();
|
|
||||||
this.persons.forEach((person) => {
|
|
||||||
participations.forEach((participation) => {
|
|
||||||
if (person.id === participation.id) {
|
|
||||||
//console.log(person.id);
|
|
||||||
personsAssociated.push(person);
|
|
||||||
personsNotAssociated = personsNotAssociated.filter(
|
|
||||||
(p) => p !== person,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
personsAssociated: personsAssociated,
|
|
||||||
personsNotAssociated: personsNotAssociated,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
getCourseParticipations() {
|
|
||||||
let participations = [];
|
|
||||||
this.accompanyingCourse.participations.forEach((participation) => {
|
|
||||||
if (!participation.endDate) {
|
|
||||||
participations.push(participation.person);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return participations;
|
|
||||||
},
|
|
||||||
addNewPersons({ selected, modal }) {
|
|
||||||
console.log("@@@ CLICK button addNewPersons", selected);
|
|
||||||
selected.forEach((item) => {
|
|
||||||
this.$store.dispatch("addPersonsInvolved", item);
|
|
||||||
}, this);
|
|
||||||
this.$refs.addPersons.resetSearch(); // to cast child method
|
|
||||||
modal.showModal = false;
|
|
||||||
this.setPersonsInBloc();
|
|
||||||
},
|
|
||||||
addSuggestedEntity(person) {
|
|
||||||
this.$store.dispatch("addPersonsInvolved", {
|
|
||||||
result: person,
|
|
||||||
type: "person",
|
|
||||||
});
|
|
||||||
this.setPersonsInBloc();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
<template>
|
<template>
|
||||||
<li>
|
<li>
|
||||||
<span :title="person.text" @click.prevent="$emit('remove', person)">
|
<span :title="person.text" @click.prevent="$emit('remove', person)">
|
||||||
<span class="chill_denomination">
|
<span class="chill_denomination">
|
||||||
<person-text :person="person" :is-cut="true" />
|
<person-text :person="person" :is-cut="true" />
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
|
import PersonText from "ChillPersonAssets/vuejs/_components/Entity/PersonText.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PersonBadge",
|
name: "PersonBadge",
|
||||||
props: ["person"],
|
props: ["person"],
|
||||||
components: {
|
components: {
|
||||||
PersonText,
|
PersonText,
|
||||||
},
|
},
|
||||||
// computed: {
|
// computed: {
|
||||||
// textCutted() {
|
// textCutted() {
|
||||||
// let more = (this.person.text.length > 15) ?'…' : '';
|
// let more = (this.person.text.length > 15) ?'…' : '';
|
||||||
// return this.person.text.slice(0,15) + more;
|
// return this.person.text.slice(0,15) + more;
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
emits: ["remove"],
|
emits: ["remove"],
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +1,38 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="item-bloc" :style="{ 'flex-basis': blocWidth }">
|
<div class="item-bloc" :style="{ 'flex-basis': blocWidth }">
|
||||||
<div class="item-row">
|
<div class="item-row">
|
||||||
<div class="item-col">
|
<div class="item-col">
|
||||||
<h4>{{ $t(bloc.title) }}</h4>
|
<h4>{{ $t(bloc.title) }}</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-col">
|
<div class="item-col">
|
||||||
<ul class="list-suggest remove-items">
|
<ul class="list-suggest remove-items">
|
||||||
<person-badge
|
<person-badge
|
||||||
v-for="person in bloc.persons"
|
v-for="person in bloc.persons"
|
||||||
:key="person.id"
|
:key="person.id"
|
||||||
:person="person"
|
:person="person"
|
||||||
@remove="removePerson"
|
@remove="removePerson"
|
||||||
/>
|
/>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import PersonBadge from "./PersonBadge.vue";
|
import PersonBadge from "./PersonBadge.vue";
|
||||||
export default {
|
export default {
|
||||||
name: "PersonsBloc",
|
name: "PersonsBloc",
|
||||||
components: {
|
components: {
|
||||||
PersonBadge,
|
PersonBadge,
|
||||||
},
|
},
|
||||||
props: ["bloc", "setPersonsInBloc", "blocWidth"],
|
props: ["bloc", "setPersonsInBloc", "blocWidth"],
|
||||||
methods: {
|
methods: {
|
||||||
removePerson(item) {
|
removePerson(item) {
|
||||||
console.log("@@ CLICK remove person: item", item);
|
console.log("@@ CLICK remove person: item", item);
|
||||||
this.$store.dispatch("removePersonInvolved", item);
|
this.$store.dispatch("removePersonInvolved", item);
|
||||||
this.setPersonsInBloc();
|
this.setPersonsInBloc();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,32 @@
|
|||||||
<template>
|
<template>
|
||||||
<teleport to="#location">
|
<teleport to="#location">
|
||||||
<div class="mb-3 row">
|
<div class="mb-3 row">
|
||||||
<label :class="locationClassList">
|
<label :class="locationClassList">
|
||||||
{{ trans(ACTIVITY_LOCATION) }}
|
{{ trans(ACTIVITY_LOCATION) }}
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<VueMultiselect
|
<VueMultiselect
|
||||||
name="selectLocation"
|
name="selectLocation"
|
||||||
id="selectLocation"
|
id="selectLocation"
|
||||||
label="name"
|
label="name"
|
||||||
track-by="id"
|
track-by="id"
|
||||||
open-direction="top"
|
open-direction="top"
|
||||||
:multiple="false"
|
:multiple="false"
|
||||||
:searchable="true"
|
:searchable="true"
|
||||||
:placeholder="trans(ACTIVITY_CHOOSE_LOCATION)"
|
:placeholder="trans(ACTIVITY_CHOOSE_LOCATION)"
|
||||||
:custom-label="customLabel"
|
:custom-label="customLabel"
|
||||||
:select-label="trans(MULTISELECT_SELECT_LABEL)"
|
:select-label="trans(MULTISELECT_SELECT_LABEL)"
|
||||||
:deselect-label="trans(MULTISELECT_DESELECT_LABEL)"
|
:deselect-label="trans(MULTISELECT_DESELECT_LABEL)"
|
||||||
:selected-label="trans(MULTISELECT_SELECTED_LABEL)"
|
:selected-label="trans(MULTISELECT_SELECTED_LABEL)"
|
||||||
:options="availableLocations"
|
:options="availableLocations"
|
||||||
group-values="locations"
|
group-values="locations"
|
||||||
group-label="locationGroup"
|
group-label="locationGroup"
|
||||||
v-model="location"
|
v-model="location"
|
||||||
/>
|
/>
|
||||||
<new-location v-bind:available-locations="availableLocations" />
|
<new-location v-bind:available-locations="availableLocations" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</teleport>
|
</teleport>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -35,60 +35,60 @@ import VueMultiselect from "vue-multiselect";
|
|||||||
import NewLocation from "./Location/NewLocation.vue";
|
import NewLocation from "./Location/NewLocation.vue";
|
||||||
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||||
import {
|
import {
|
||||||
trans,
|
trans,
|
||||||
ACTIVITY_LOCATION,
|
ACTIVITY_LOCATION,
|
||||||
ACTIVITY_CHOOSE_LOCATION,
|
ACTIVITY_CHOOSE_LOCATION,
|
||||||
MULTISELECT_SELECT_LABEL,
|
MULTISELECT_SELECT_LABEL,
|
||||||
MULTISELECT_DESELECT_LABEL,
|
MULTISELECT_DESELECT_LABEL,
|
||||||
MULTISELECT_SELECTED_LABEL,
|
MULTISELECT_SELECTED_LABEL,
|
||||||
} from "translator";
|
} from "translator";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Location",
|
name: "Location",
|
||||||
components: {
|
components: {
|
||||||
NewLocation,
|
NewLocation,
|
||||||
VueMultiselect,
|
VueMultiselect,
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
trans,
|
|
||||||
ACTIVITY_LOCATION,
|
|
||||||
ACTIVITY_CHOOSE_LOCATION,
|
|
||||||
MULTISELECT_SELECT_LABEL,
|
|
||||||
MULTISELECT_DESELECT_LABEL,
|
|
||||||
MULTISELECT_SELECTED_LABEL,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
locationClassList: `col-form-label col-sm-4 ${document.querySelector("input#chill_activitybundle_activity_location").getAttribute("required") ? "required" : ""}`,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState(["activity", "availableLocations"]),
|
|
||||||
...mapGetters(["suggestedEntities"]),
|
|
||||||
location: {
|
|
||||||
get() {
|
|
||||||
return this.activity.location;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.$store.dispatch("updateLocation", value);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
setup() {
|
||||||
methods: {
|
return {
|
||||||
labelAccompanyingCourseLocation(value) {
|
trans,
|
||||||
return `${value.address.text} (${localizeString(value.locationType.title)})`;
|
ACTIVITY_LOCATION,
|
||||||
|
ACTIVITY_CHOOSE_LOCATION,
|
||||||
|
MULTISELECT_SELECT_LABEL,
|
||||||
|
MULTISELECT_DESELECT_LABEL,
|
||||||
|
MULTISELECT_SELECTED_LABEL,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
customLabel(value) {
|
data() {
|
||||||
return value.locationType
|
return {
|
||||||
? value.name
|
locationClassList: `col-form-label col-sm-4 ${document.querySelector("input#chill_activitybundle_activity_location").getAttribute("required") ? "required" : ""}`,
|
||||||
? value.name === "__AccompanyingCourseLocation__"
|
};
|
||||||
? this.labelAccompanyingCourseLocation(value)
|
},
|
||||||
: `${value.name} (${localizeString(value.locationType.title)})`
|
computed: {
|
||||||
: localizeString(value.locationType.title)
|
...mapState(["activity", "availableLocations"]),
|
||||||
: "";
|
...mapGetters(["suggestedEntities"]),
|
||||||
|
location: {
|
||||||
|
get() {
|
||||||
|
return this.activity.location;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.$store.dispatch("updateLocation", value);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
labelAccompanyingCourseLocation(value) {
|
||||||
|
return `${value.address.text} (${localizeString(value.locationType.title)})`;
|
||||||
|
},
|
||||||
|
customLabel(value) {
|
||||||
|
return value.locationType
|
||||||
|
? value.name
|
||||||
|
? value.name === "__AccompanyingCourseLocation__"
|
||||||
|
? this.labelAccompanyingCourseLocation(value)
|
||||||
|
: `${value.name} (${localizeString(value.locationType.title)})`
|
||||||
|
: localizeString(value.locationType.title)
|
||||||
|
: "";
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,114 +1,123 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li>
|
<li>
|
||||||
<a class="btn btn-sm btn-create" @click="openModal">
|
<a class="btn btn-sm btn-create" @click="openModal">
|
||||||
{{ trans(ACTIVITY_CREATE_NEW_LOCATION) }}
|
{{ trans(ACTIVITY_CREATE_NEW_LOCATION) }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<teleport to="body">
|
<teleport to="body">
|
||||||
<modal
|
<modal
|
||||||
v-if="modal.showModal"
|
v-if="modal.showModal"
|
||||||
:modalDialogClass="modal.modalDialogClass"
|
:modalDialogClass="modal.modalDialogClass"
|
||||||
@close="modal.showModal = false"
|
@close="modal.showModal = false"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<h3 class="modal-title">
|
<h3 class="modal-title">
|
||||||
{{ trans(ACTIVITY_CREATE_NEW_LOCATION) }}
|
{{ trans(ACTIVITY_CREATE_NEW_LOCATION) }}
|
||||||
</h3>
|
</h3>
|
||||||
</template>
|
</template>
|
||||||
<template #body>
|
<template #body>
|
||||||
<form>
|
<form>
|
||||||
<div class="alert alert-warning" v-if="errors.length">
|
<div class="alert alert-warning" v-if="errors.length">
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="(e, i) in errors" :key="i">
|
<li v-for="(e, i) in errors" :key="i">
|
||||||
{{ e }}
|
{{ e }}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-floating mb-3">
|
<div class="form-floating mb-3">
|
||||||
<select
|
<select
|
||||||
class="form-select form-select-lg"
|
class="form-select form-select-lg"
|
||||||
id="type"
|
id="type"
|
||||||
required
|
required
|
||||||
v-model="selectType"
|
v-model="selectType"
|
||||||
>
|
>
|
||||||
<option selected disabled value="">
|
<option selected disabled value="">
|
||||||
{{ trans(ACTIVITY_CHOOSE_LOCATION_TYPE) }}
|
{{ trans(ACTIVITY_CHOOSE_LOCATION_TYPE) }}
|
||||||
</option>
|
</option>
|
||||||
<option v-for="t in locationTypes" :value="t" :key="t.id">
|
<option
|
||||||
{{ localizeString(t.title) }}
|
v-for="t in locationTypes"
|
||||||
</option>
|
:value="t"
|
||||||
</select>
|
:key="t.id"
|
||||||
<label>{{ trans(ACTIVITY_LOCATION_FIELDS_TYPE) }}</label>
|
>
|
||||||
</div>
|
{{ localizeString(t.title) }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<label>{{
|
||||||
|
trans(ACTIVITY_LOCATION_FIELDS_TYPE)
|
||||||
|
}}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-floating mb-3">
|
<div class="form-floating mb-3">
|
||||||
<input
|
<input
|
||||||
class="form-control form-control-lg"
|
class="form-control form-control-lg"
|
||||||
id="name"
|
id="name"
|
||||||
v-model="inputName"
|
v-model="inputName"
|
||||||
placeholder
|
placeholder
|
||||||
/>
|
/>
|
||||||
<label for="name">{{
|
<label for="name">{{
|
||||||
trans(ACTIVITY_LOCATION_FIELDS_NAME)
|
trans(ACTIVITY_LOCATION_FIELDS_NAME)
|
||||||
}}</label>
|
}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<add-address
|
<add-address
|
||||||
:context="addAddress.context"
|
:context="addAddress.context"
|
||||||
:options="addAddress.options"
|
:options="addAddress.options"
|
||||||
:addressChangedCallback="submitNewAddress"
|
:addressChangedCallback="submitNewAddress"
|
||||||
v-if="showAddAddress"
|
v-if="showAddAddress"
|
||||||
ref="addAddress"
|
ref="addAddress"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="form-floating mb-3" v-if="showContactData">
|
<div class="form-floating mb-3" v-if="showContactData">
|
||||||
<input
|
<input
|
||||||
class="form-control form-control-lg"
|
class="form-control form-control-lg"
|
||||||
id="phonenumber1"
|
id="phonenumber1"
|
||||||
v-model="inputPhonenumber1"
|
v-model="inputPhonenumber1"
|
||||||
placeholder
|
placeholder
|
||||||
/>
|
/>
|
||||||
<label for="phonenumber1">{{
|
<label for="phonenumber1">{{
|
||||||
trans(ACTIVITY_LOCATION_FIELDS_PHONENUMBER1)
|
trans(ACTIVITY_LOCATION_FIELDS_PHONENUMBER1)
|
||||||
}}</label>
|
}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-floating mb-3" v-if="hasPhonenumber1">
|
<div class="form-floating mb-3" v-if="hasPhonenumber1">
|
||||||
<input
|
<input
|
||||||
class="form-control form-control-lg"
|
class="form-control form-control-lg"
|
||||||
id="phonenumber2"
|
id="phonenumber2"
|
||||||
v-model="inputPhonenumber2"
|
v-model="inputPhonenumber2"
|
||||||
placeholder
|
placeholder
|
||||||
/>
|
/>
|
||||||
<label for="phonenumber2">{{
|
<label for="phonenumber2">{{
|
||||||
trans(ACTIVITY_LOCATION_FIELDS_PHONENUMBER2)
|
trans(ACTIVITY_LOCATION_FIELDS_PHONENUMBER2)
|
||||||
}}</label>
|
}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-floating mb-3" v-if="showContactData">
|
<div class="form-floating mb-3" v-if="showContactData">
|
||||||
<input
|
<input
|
||||||
class="form-control form-control-lg"
|
class="form-control form-control-lg"
|
||||||
id="email"
|
id="email"
|
||||||
v-model="inputEmail"
|
v-model="inputEmail"
|
||||||
placeholder
|
placeholder
|
||||||
/>
|
/>
|
||||||
<label for="email">{{
|
<label for="email">{{
|
||||||
trans(ACTIVITY_LOCATION_FIELDS_EMAIL)
|
trans(ACTIVITY_LOCATION_FIELDS_EMAIL)
|
||||||
}}</label>
|
}}</label>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<button class="btn btn-save" @click.prevent="saveNewLocation">
|
<button
|
||||||
{{ trans(SAVE) }}
|
class="btn btn-save"
|
||||||
</button>
|
@click.prevent="saveNewLocation"
|
||||||
</template>
|
>
|
||||||
</modal>
|
{{ trans(SAVE) }}
|
||||||
</teleport>
|
</button>
|
||||||
</div>
|
</template>
|
||||||
|
</modal>
|
||||||
|
</teleport>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -119,240 +128,241 @@ import { getLocationTypes } from "../../api";
|
|||||||
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
||||||
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||||
import {
|
import {
|
||||||
SAVE,
|
SAVE,
|
||||||
ACTIVITY_LOCATION_FIELDS_EMAIL,
|
ACTIVITY_LOCATION_FIELDS_EMAIL,
|
||||||
ACTIVITY_LOCATION_FIELDS_PHONENUMBER1,
|
ACTIVITY_LOCATION_FIELDS_PHONENUMBER1,
|
||||||
ACTIVITY_LOCATION_FIELDS_PHONENUMBER2,
|
ACTIVITY_LOCATION_FIELDS_PHONENUMBER2,
|
||||||
ACTIVITY_LOCATION_FIELDS_NAME,
|
ACTIVITY_LOCATION_FIELDS_NAME,
|
||||||
ACTIVITY_LOCATION_FIELDS_TYPE,
|
ACTIVITY_LOCATION_FIELDS_TYPE,
|
||||||
ACTIVITY_CHOOSE_LOCATION_TYPE,
|
ACTIVITY_CHOOSE_LOCATION_TYPE,
|
||||||
ACTIVITY_CREATE_NEW_LOCATION,
|
ACTIVITY_CREATE_NEW_LOCATION,
|
||||||
ACTIVITY_EDIT_ADDRESS,
|
ACTIVITY_EDIT_ADDRESS,
|
||||||
ACTIVITY_CREATE_ADDRESS,
|
ACTIVITY_CREATE_ADDRESS,
|
||||||
trans,
|
trans,
|
||||||
} from "translator";
|
} from "translator";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "NewLocation",
|
name: "NewLocation",
|
||||||
components: {
|
components: {
|
||||||
Modal,
|
Modal,
|
||||||
AddAddress,
|
AddAddress,
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
trans,
|
|
||||||
SAVE,
|
|
||||||
ACTIVITY_LOCATION_FIELDS_EMAIL,
|
|
||||||
ACTIVITY_LOCATION_FIELDS_PHONENUMBER1,
|
|
||||||
ACTIVITY_LOCATION_FIELDS_PHONENUMBER2,
|
|
||||||
ACTIVITY_LOCATION_FIELDS_NAME,
|
|
||||||
ACTIVITY_LOCATION_FIELDS_TYPE,
|
|
||||||
ACTIVITY_CHOOSE_LOCATION_TYPE,
|
|
||||||
ACTIVITY_CREATE_NEW_LOCATION,
|
|
||||||
ACTIVITY_EDIT_ADDRESS,
|
|
||||||
ACTIVITY_CREATE_ADDRESS,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
props: ["availableLocations"],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
errors: [],
|
|
||||||
selected: {
|
|
||||||
type: null,
|
|
||||||
name: null,
|
|
||||||
addressId: null,
|
|
||||||
phonenumber1: null,
|
|
||||||
phonenumber2: null,
|
|
||||||
email: null,
|
|
||||||
},
|
|
||||||
locationTypes: [],
|
|
||||||
modal: {
|
|
||||||
showModal: false,
|
|
||||||
modalDialogClass: "modal-dialog-scrollable modal-xl",
|
|
||||||
},
|
|
||||||
addAddress: {
|
|
||||||
options: {
|
|
||||||
button: {
|
|
||||||
text: {
|
|
||||||
create: ACTIVITY_CREATE_ADDRESS,
|
|
||||||
edit: ACTIVITY_EDIT_ADDRESS,
|
|
||||||
},
|
|
||||||
size: "btn-sm",
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
create: ACTIVITY_CREATE_ADDRESS,
|
|
||||||
edit: ACTIVITY_EDIT_ADDRESS,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
context: {
|
|
||||||
target: {
|
|
||||||
//name, id
|
|
||||||
},
|
|
||||||
edit: false,
|
|
||||||
addressId: null,
|
|
||||||
defaults: window.addaddress,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState(["activity"]),
|
|
||||||
selectType: {
|
|
||||||
get() {
|
|
||||||
return this.selected.type;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.selected.type = value;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
inputName: {
|
setup() {
|
||||||
get() {
|
return {
|
||||||
return this.selected.name;
|
trans,
|
||||||
},
|
SAVE,
|
||||||
set(value) {
|
ACTIVITY_LOCATION_FIELDS_EMAIL,
|
||||||
this.selected.name = value;
|
ACTIVITY_LOCATION_FIELDS_PHONENUMBER1,
|
||||||
},
|
ACTIVITY_LOCATION_FIELDS_PHONENUMBER2,
|
||||||
},
|
ACTIVITY_LOCATION_FIELDS_NAME,
|
||||||
inputEmail: {
|
ACTIVITY_LOCATION_FIELDS_TYPE,
|
||||||
get() {
|
ACTIVITY_CHOOSE_LOCATION_TYPE,
|
||||||
return this.selected.email;
|
ACTIVITY_CREATE_NEW_LOCATION,
|
||||||
},
|
ACTIVITY_EDIT_ADDRESS,
|
||||||
set(value) {
|
ACTIVITY_CREATE_ADDRESS,
|
||||||
this.selected.email = value;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
inputPhonenumber1: {
|
|
||||||
get() {
|
|
||||||
return this.selected.phonenumber1;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.selected.phonenumber1 = value;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
inputPhonenumber2: {
|
|
||||||
get() {
|
|
||||||
return this.selected.phonenumber2;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.selected.phonenumber2 = value;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hasPhonenumber1() {
|
|
||||||
return (
|
|
||||||
this.selected.phonenumber1 !== null && this.selected.phonenumber1 !== ""
|
|
||||||
);
|
|
||||||
},
|
|
||||||
showAddAddress() {
|
|
||||||
let cond = false;
|
|
||||||
if (this.selected.type) {
|
|
||||||
if (this.selected.type.addressRequired !== "never") {
|
|
||||||
cond = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cond;
|
|
||||||
},
|
|
||||||
showContactData() {
|
|
||||||
let cond = false;
|
|
||||||
if (this.selected.type) {
|
|
||||||
if (this.selected.type.contactData !== "never") {
|
|
||||||
cond = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cond;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.getLocationTypesList();
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
localizeString,
|
|
||||||
checkForm() {
|
|
||||||
let cond = true;
|
|
||||||
this.errors = [];
|
|
||||||
if (!this.selected.type) {
|
|
||||||
this.errors.push("Type de localisation requis");
|
|
||||||
cond = false;
|
|
||||||
} else {
|
|
||||||
if (
|
|
||||||
this.selected.type.addressRequired === "required" &&
|
|
||||||
!this.selected.addressId
|
|
||||||
) {
|
|
||||||
this.errors.push("Adresse requise");
|
|
||||||
cond = false;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
this.selected.type.contactData === "required" &&
|
|
||||||
!this.selected.phonenumber1
|
|
||||||
) {
|
|
||||||
this.errors.push("Numéro de téléphone requis");
|
|
||||||
cond = false;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
this.selected.type.contactData === "required" &&
|
|
||||||
!this.selected.email
|
|
||||||
) {
|
|
||||||
this.errors.push("Adresse email requise");
|
|
||||||
cond = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cond;
|
|
||||||
},
|
|
||||||
getLocationTypesList() {
|
|
||||||
getLocationTypes().then((results) => {
|
|
||||||
this.locationTypes = results.filter(
|
|
||||||
(t) => t.availableForUsers === true,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
openModal() {
|
|
||||||
this.modal.showModal = true;
|
|
||||||
},
|
|
||||||
saveNewLocation() {
|
|
||||||
if (this.checkForm()) {
|
|
||||||
let body = {
|
|
||||||
type: "location",
|
|
||||||
name: this.selected.name,
|
|
||||||
locationType: {
|
|
||||||
id: this.selected.type.id,
|
|
||||||
type: "location-type",
|
|
||||||
},
|
|
||||||
phonenumber1: this.selected.phonenumber1,
|
|
||||||
phonenumber2: this.selected.phonenumber2,
|
|
||||||
email: this.selected.email,
|
|
||||||
};
|
};
|
||||||
if (this.selected.addressId) {
|
},
|
||||||
body = Object.assign(body, {
|
props: ["availableLocations"],
|
||||||
address: {
|
data() {
|
||||||
id: this.selected.addressId,
|
return {
|
||||||
|
errors: [],
|
||||||
|
selected: {
|
||||||
|
type: null,
|
||||||
|
name: null,
|
||||||
|
addressId: null,
|
||||||
|
phonenumber1: null,
|
||||||
|
phonenumber2: null,
|
||||||
|
email: null,
|
||||||
},
|
},
|
||||||
});
|
locationTypes: [],
|
||||||
}
|
modal: {
|
||||||
|
showModal: false,
|
||||||
makeFetch("POST", "/api/1.0/main/location.json", body)
|
modalDialogClass: "modal-dialog-scrollable modal-xl",
|
||||||
.then((response) => {
|
},
|
||||||
this.$store.dispatch("addAvailableLocationGroup", {
|
addAddress: {
|
||||||
locationGroup: "Localisations nouvellement créées",
|
options: {
|
||||||
locations: [response],
|
button: {
|
||||||
});
|
text: {
|
||||||
this.$store.dispatch("updateLocation", response);
|
create: ACTIVITY_CREATE_ADDRESS,
|
||||||
this.modal.showModal = false;
|
edit: ACTIVITY_EDIT_ADDRESS,
|
||||||
})
|
},
|
||||||
.catch((error) => {
|
size: "btn-sm",
|
||||||
if (error.name === "ValidationException") {
|
},
|
||||||
for (let v of error.violations) {
|
title: {
|
||||||
this.errors.push(v);
|
create: ACTIVITY_CREATE_ADDRESS,
|
||||||
}
|
edit: ACTIVITY_EDIT_ADDRESS,
|
||||||
} else {
|
},
|
||||||
this.errors.push("An error occurred");
|
},
|
||||||
|
context: {
|
||||||
|
target: {
|
||||||
|
//name, id
|
||||||
|
},
|
||||||
|
edit: false,
|
||||||
|
addressId: null,
|
||||||
|
defaults: window.addaddress,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(["activity"]),
|
||||||
|
selectType: {
|
||||||
|
get() {
|
||||||
|
return this.selected.type;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.selected.type = value;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputName: {
|
||||||
|
get() {
|
||||||
|
return this.selected.name;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.selected.name = value;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputEmail: {
|
||||||
|
get() {
|
||||||
|
return this.selected.email;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.selected.email = value;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputPhonenumber1: {
|
||||||
|
get() {
|
||||||
|
return this.selected.phonenumber1;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.selected.phonenumber1 = value;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputPhonenumber2: {
|
||||||
|
get() {
|
||||||
|
return this.selected.phonenumber2;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.selected.phonenumber2 = value;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hasPhonenumber1() {
|
||||||
|
return (
|
||||||
|
this.selected.phonenumber1 !== null &&
|
||||||
|
this.selected.phonenumber1 !== ""
|
||||||
|
);
|
||||||
|
},
|
||||||
|
showAddAddress() {
|
||||||
|
let cond = false;
|
||||||
|
if (this.selected.type) {
|
||||||
|
if (this.selected.type.addressRequired !== "never") {
|
||||||
|
cond = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
return cond;
|
||||||
}
|
},
|
||||||
|
showContactData() {
|
||||||
|
let cond = false;
|
||||||
|
if (this.selected.type) {
|
||||||
|
if (this.selected.type.contactData !== "never") {
|
||||||
|
cond = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cond;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
submitNewAddress(payload) {
|
mounted() {
|
||||||
this.selected.addressId = payload.addressId;
|
this.getLocationTypesList();
|
||||||
this.addAddress.context.addressId = payload.addressId;
|
},
|
||||||
this.addAddress.context.edit = true;
|
methods: {
|
||||||
|
localizeString,
|
||||||
|
checkForm() {
|
||||||
|
let cond = true;
|
||||||
|
this.errors = [];
|
||||||
|
if (!this.selected.type) {
|
||||||
|
this.errors.push("Type de localisation requis");
|
||||||
|
cond = false;
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
this.selected.type.addressRequired === "required" &&
|
||||||
|
!this.selected.addressId
|
||||||
|
) {
|
||||||
|
this.errors.push("Adresse requise");
|
||||||
|
cond = false;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
this.selected.type.contactData === "required" &&
|
||||||
|
!this.selected.phonenumber1
|
||||||
|
) {
|
||||||
|
this.errors.push("Numéro de téléphone requis");
|
||||||
|
cond = false;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
this.selected.type.contactData === "required" &&
|
||||||
|
!this.selected.email
|
||||||
|
) {
|
||||||
|
this.errors.push("Adresse email requise");
|
||||||
|
cond = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cond;
|
||||||
|
},
|
||||||
|
getLocationTypesList() {
|
||||||
|
getLocationTypes().then((results) => {
|
||||||
|
this.locationTypes = results.filter(
|
||||||
|
(t) => t.availableForUsers === true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
openModal() {
|
||||||
|
this.modal.showModal = true;
|
||||||
|
},
|
||||||
|
saveNewLocation() {
|
||||||
|
if (this.checkForm()) {
|
||||||
|
let body = {
|
||||||
|
type: "location",
|
||||||
|
name: this.selected.name,
|
||||||
|
locationType: {
|
||||||
|
id: this.selected.type.id,
|
||||||
|
type: "location-type",
|
||||||
|
},
|
||||||
|
phonenumber1: this.selected.phonenumber1,
|
||||||
|
phonenumber2: this.selected.phonenumber2,
|
||||||
|
email: this.selected.email,
|
||||||
|
};
|
||||||
|
if (this.selected.addressId) {
|
||||||
|
body = Object.assign(body, {
|
||||||
|
address: {
|
||||||
|
id: this.selected.addressId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
makeFetch("POST", "/api/1.0/main/location.json", body)
|
||||||
|
.then((response) => {
|
||||||
|
this.$store.dispatch("addAvailableLocationGroup", {
|
||||||
|
locationGroup: "Localisations nouvellement créées",
|
||||||
|
locations: [response],
|
||||||
|
});
|
||||||
|
this.$store.dispatch("updateLocation", response);
|
||||||
|
this.modal.showModal = false;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
if (error.name === "ValidationException") {
|
||||||
|
for (let v of error.violations) {
|
||||||
|
this.errors.push(v);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.errors.push("An error occurred");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
submitNewAddress(payload) {
|
||||||
|
this.selected.addressId = payload.addressId;
|
||||||
|
this.addAddress.context.addressId = payload.addressId;
|
||||||
|
this.addAddress.context.edit = true;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,98 +1,103 @@
|
|||||||
<template>
|
<template>
|
||||||
<teleport to="#social-issues-acc">
|
<teleport to="#social-issues-acc">
|
||||||
<div class="mb-3 row">
|
<div class="mb-3 row">
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<label :class="socialIssuesClassList">{{
|
<label :class="socialIssuesClassList">{{
|
||||||
trans(ACTIVITY_SOCIAL_ISSUES)
|
trans(ACTIVITY_SOCIAL_ISSUES)
|
||||||
}}</label>
|
}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-8">
|
<div class="col-8">
|
||||||
<check-social-issue
|
<check-social-issue
|
||||||
v-for="issue in socialIssuesList"
|
v-for="issue in socialIssuesList"
|
||||||
:key="issue.id"
|
:key="issue.id"
|
||||||
:issue="issue"
|
:issue="issue"
|
||||||
:selection="socialIssuesSelected"
|
:selection="socialIssuesSelected"
|
||||||
@updateSelected="updateIssuesSelected"
|
@updateSelected="updateIssuesSelected"
|
||||||
>
|
>
|
||||||
</check-social-issue>
|
</check-social-issue>
|
||||||
|
|
||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
<VueMultiselect
|
<VueMultiselect
|
||||||
name="otherIssues"
|
name="otherIssues"
|
||||||
label="text"
|
label="text"
|
||||||
track-by="id"
|
track-by="id"
|
||||||
open-direction="bottom"
|
open-direction="bottom"
|
||||||
:close-on-select="true"
|
:close-on-select="true"
|
||||||
:preserve-search="false"
|
:preserve-search="false"
|
||||||
:reset-after="true"
|
:reset-after="true"
|
||||||
:hide-selected="true"
|
:hide-selected="true"
|
||||||
:taggable="false"
|
:taggable="false"
|
||||||
:multiple="false"
|
:multiple="false"
|
||||||
:searchable="true"
|
:searchable="true"
|
||||||
:allow-empty="true"
|
:allow-empty="true"
|
||||||
:show-labels="false"
|
:show-labels="false"
|
||||||
:loading="issueIsLoading"
|
:loading="issueIsLoading"
|
||||||
:placeholder="trans(ACTIVITY_CHOOSE_OTHER_SOCIAL_ISSUE)"
|
:placeholder="trans(ACTIVITY_CHOOSE_OTHER_SOCIAL_ISSUE)"
|
||||||
:options="socialIssuesOther"
|
:options="socialIssuesOther"
|
||||||
@select="addIssueInList"
|
@select="addIssueInList"
|
||||||
>
|
>
|
||||||
</VueMultiselect>
|
</VueMultiselect>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3 row">
|
|
||||||
<div class="col-4">
|
|
||||||
<label :class="socialActionsClassList">{{
|
|
||||||
trans(ACTIVITY_SOCIAL_ACTIONS)
|
|
||||||
}}</label>
|
|
||||||
</div>
|
|
||||||
<div class="col-8">
|
|
||||||
<div v-if="actionIsLoading === true">
|
|
||||||
<i class="chill-green fa fa-circle-o-notch fa-spin fa-lg"></i>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span
|
<div class="mb-3 row">
|
||||||
v-else-if="socialIssuesSelected.length === 0"
|
<div class="col-4">
|
||||||
class="inline-choice chill-no-data-statement mt-3"
|
<label :class="socialActionsClassList">{{
|
||||||
>
|
trans(ACTIVITY_SOCIAL_ACTIONS)
|
||||||
{{ trans(ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE) }}
|
}}</label>
|
||||||
</span>
|
</div>
|
||||||
|
<div class="col-8">
|
||||||
|
<div v-if="actionIsLoading === true">
|
||||||
|
<i
|
||||||
|
class="chill-green fa fa-circle-o-notch fa-spin fa-lg"
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<template
|
<span
|
||||||
v-else-if="
|
v-else-if="socialIssuesSelected.length === 0"
|
||||||
socialActionsList.length > 0 &&
|
class="inline-choice chill-no-data-statement mt-3"
|
||||||
(socialIssuesSelected.length || socialActionsSelected.length)
|
>
|
||||||
"
|
{{ trans(ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE) }}
|
||||||
>
|
</span>
|
||||||
<div
|
|
||||||
id="actionsList"
|
|
||||||
v-for="group in socialActionsList"
|
|
||||||
:key="group.issue"
|
|
||||||
>
|
|
||||||
<span class="badge bg-chill-l-gray text-dark">{{
|
|
||||||
group.issue
|
|
||||||
}}</span>
|
|
||||||
<check-social-action
|
|
||||||
v-for="action in group.actions"
|
|
||||||
:key="action.id"
|
|
||||||
:action="action"
|
|
||||||
:selection="socialActionsSelected"
|
|
||||||
@updateSelected="updateActionsSelected"
|
|
||||||
>
|
|
||||||
</check-social-action>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<span
|
<template
|
||||||
v-else-if="actionAreLoaded && socialActionsList.length === 0"
|
v-else-if="
|
||||||
class="inline-choice chill-no-data-statement mt-3"
|
socialActionsList.length > 0 &&
|
||||||
>
|
(socialIssuesSelected.length ||
|
||||||
{{ trans(ACTIVITY_SOCIAL_ACTION_LIST_EMPTY) }}
|
socialActionsSelected.length)
|
||||||
</span>
|
"
|
||||||
</div>
|
>
|
||||||
</div>
|
<div
|
||||||
</teleport>
|
id="actionsList"
|
||||||
|
v-for="group in socialActionsList"
|
||||||
|
:key="group.issue"
|
||||||
|
>
|
||||||
|
<span class="badge bg-chill-l-gray text-dark">{{
|
||||||
|
group.issue
|
||||||
|
}}</span>
|
||||||
|
<check-social-action
|
||||||
|
v-for="action in group.actions"
|
||||||
|
:key="action.id"
|
||||||
|
:action="action"
|
||||||
|
:selection="socialActionsSelected"
|
||||||
|
@updateSelected="updateActionsSelected"
|
||||||
|
>
|
||||||
|
</check-social-action>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<span
|
||||||
|
v-else-if="
|
||||||
|
actionAreLoaded && socialActionsList.length === 0
|
||||||
|
"
|
||||||
|
class="inline-choice chill-no-data-statement mt-3"
|
||||||
|
>
|
||||||
|
{{ trans(ACTIVITY_SOCIAL_ACTION_LIST_EMPTY) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</teleport>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -101,174 +106,175 @@ import CheckSocialIssue from "./SocialIssuesAcc/CheckSocialIssue.vue";
|
|||||||
import CheckSocialAction from "./SocialIssuesAcc/CheckSocialAction.vue";
|
import CheckSocialAction from "./SocialIssuesAcc/CheckSocialAction.vue";
|
||||||
import { getSocialIssues, getSocialActionByIssue } from "../api.js";
|
import { getSocialIssues, getSocialActionByIssue } from "../api.js";
|
||||||
import {
|
import {
|
||||||
ACTIVITY_SOCIAL_ACTION_LIST_EMPTY,
|
ACTIVITY_SOCIAL_ACTION_LIST_EMPTY,
|
||||||
ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE,
|
ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE,
|
||||||
ACTIVITY_SOCIAL_ACTIONS,
|
ACTIVITY_SOCIAL_ACTIONS,
|
||||||
ACTIVITY_SOCIAL_ISSUES,
|
ACTIVITY_SOCIAL_ISSUES,
|
||||||
ACTIVITY_CHOOSE_OTHER_SOCIAL_ISSUE,
|
ACTIVITY_CHOOSE_OTHER_SOCIAL_ISSUE,
|
||||||
trans,
|
trans,
|
||||||
} from "translator";
|
} from "translator";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "SocialIssuesAcc",
|
name: "SocialIssuesAcc",
|
||||||
components: {
|
components: {
|
||||||
CheckSocialIssue,
|
CheckSocialIssue,
|
||||||
CheckSocialAction,
|
CheckSocialAction,
|
||||||
VueMultiselect,
|
VueMultiselect,
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
trans,
|
|
||||||
ACTIVITY_SOCIAL_ACTION_LIST_EMPTY,
|
|
||||||
ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE,
|
|
||||||
ACTIVITY_SOCIAL_ACTIONS,
|
|
||||||
ACTIVITY_SOCIAL_ISSUES,
|
|
||||||
ACTIVITY_CHOOSE_OTHER_SOCIAL_ISSUE,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
issueIsLoading: false,
|
|
||||||
actionIsLoading: false,
|
|
||||||
actionAreLoaded: false,
|
|
||||||
socialIssuesClassList: {
|
|
||||||
"col-form-label": true,
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
socialActionsClassList: {
|
|
||||||
"col-form-label": true,
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
socialIssuesList() {
|
|
||||||
return this.$store.state.activity.accompanyingPeriod.socialIssues;
|
|
||||||
},
|
},
|
||||||
socialIssuesSelected() {
|
setup() {
|
||||||
return this.$store.state.activity.socialIssues;
|
return {
|
||||||
|
trans,
|
||||||
|
ACTIVITY_SOCIAL_ACTION_LIST_EMPTY,
|
||||||
|
ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE,
|
||||||
|
ACTIVITY_SOCIAL_ACTIONS,
|
||||||
|
ACTIVITY_SOCIAL_ISSUES,
|
||||||
|
ACTIVITY_CHOOSE_OTHER_SOCIAL_ISSUE,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
socialIssuesOther() {
|
data() {
|
||||||
return this.$store.state.socialIssuesOther;
|
return {
|
||||||
|
issueIsLoading: false,
|
||||||
|
actionIsLoading: false,
|
||||||
|
actionAreLoaded: false,
|
||||||
|
socialIssuesClassList: {
|
||||||
|
"col-form-label": true,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
socialActionsClassList: {
|
||||||
|
"col-form-label": true,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
},
|
},
|
||||||
socialActionsList() {
|
computed: {
|
||||||
return this.$store.getters.socialActionsListSorted;
|
socialIssuesList() {
|
||||||
|
return this.$store.state.activity.accompanyingPeriod.socialIssues;
|
||||||
|
},
|
||||||
|
socialIssuesSelected() {
|
||||||
|
return this.$store.state.activity.socialIssues;
|
||||||
|
},
|
||||||
|
socialIssuesOther() {
|
||||||
|
return this.$store.state.socialIssuesOther;
|
||||||
|
},
|
||||||
|
socialActionsList() {
|
||||||
|
return this.$store.getters.socialActionsListSorted;
|
||||||
|
},
|
||||||
|
socialActionsSelected() {
|
||||||
|
return this.$store.state.activity.socialActions;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
socialActionsSelected() {
|
mounted() {
|
||||||
return this.$store.state.activity.socialActions;
|
/* Load classNames after element is present */
|
||||||
},
|
const socialActionsEl = document.querySelector(
|
||||||
},
|
"input#chill_activitybundle_activity_socialActions",
|
||||||
mounted() {
|
);
|
||||||
/* Load classNames after element is present */
|
if (socialActionsEl && socialActionsEl.hasAttribute("required")) {
|
||||||
const socialActionsEl = document.querySelector(
|
this.socialActionsClassList.required = true;
|
||||||
"input#chill_activitybundle_activity_socialActions",
|
|
||||||
);
|
|
||||||
if (socialActionsEl && socialActionsEl.hasAttribute("required")) {
|
|
||||||
this.socialActionsClassList.required = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const socialIssuesEl = document.querySelector(
|
|
||||||
"input#chill_activitybundle_activity_socialIssues",
|
|
||||||
);
|
|
||||||
if (socialIssuesEl && socialIssuesEl.hasAttribute("required")) {
|
|
||||||
this.socialIssuesClassList.required = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load other issues in multiselect */
|
|
||||||
this.issueIsLoading = true;
|
|
||||||
this.actionAreLoaded = false;
|
|
||||||
|
|
||||||
getSocialIssues().then((response) => {
|
|
||||||
/* Add issues to the store */
|
|
||||||
this.$store.commit("updateIssuesOther", response);
|
|
||||||
|
|
||||||
/* Add in list the issues already associated (if not yet listed) */
|
|
||||||
this.socialIssuesSelected.forEach((issue) => {
|
|
||||||
if (
|
|
||||||
this.socialIssuesList.filter((i) => i.id === issue.id).length !== 1
|
|
||||||
) {
|
|
||||||
this.$store.commit("addIssueInList", issue);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
/* Remove from multiselect the issues that are not yet in the checkbox list */
|
const socialIssuesEl = document.querySelector(
|
||||||
this.socialIssuesList.forEach((issue) => {
|
"input#chill_activitybundle_activity_socialIssues",
|
||||||
this.$store.commit("removeIssueInOther", issue);
|
);
|
||||||
});
|
if (socialIssuesEl && socialIssuesEl.hasAttribute("required")) {
|
||||||
|
this.socialIssuesClassList.required = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Filter issues */
|
/* Load other issues in multiselect */
|
||||||
this.$store.commit("filterList", "issues");
|
this.issueIsLoading = true;
|
||||||
|
this.actionAreLoaded = false;
|
||||||
|
|
||||||
/* Add in list the actions already associated (if not yet listed) */
|
getSocialIssues().then((response) => {
|
||||||
this.socialActionsSelected.forEach((action) => {
|
/* Add issues to the store */
|
||||||
this.$store.commit("addActionInList", action);
|
this.$store.commit("updateIssuesOther", response);
|
||||||
});
|
|
||||||
|
|
||||||
/* Filter actions */
|
/* Add in list the issues already associated (if not yet listed) */
|
||||||
this.$store.commit("filterList", "actions");
|
this.socialIssuesSelected.forEach((issue) => {
|
||||||
|
if (
|
||||||
|
this.socialIssuesList.filter((i) => i.id === issue.id)
|
||||||
|
.length !== 1
|
||||||
|
) {
|
||||||
|
this.$store.commit("addIssueInList", issue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.issueIsLoading = false;
|
/* Remove from multiselect the issues that are not yet in the checkbox list */
|
||||||
this.actionAreLoaded = true;
|
this.socialIssuesList.forEach((issue) => {
|
||||||
this.updateActionsList();
|
this.$store.commit("removeIssueInOther", issue);
|
||||||
});
|
});
|
||||||
},
|
|
||||||
methods: {
|
/* Filter issues */
|
||||||
/* When choosing an issue in multiselect, add it in checkboxes (as selected),
|
this.$store.commit("filterList", "issues");
|
||||||
|
|
||||||
|
/* Add in list the actions already associated (if not yet listed) */
|
||||||
|
this.socialActionsSelected.forEach((action) => {
|
||||||
|
this.$store.commit("addActionInList", action);
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Filter actions */
|
||||||
|
this.$store.commit("filterList", "actions");
|
||||||
|
|
||||||
|
this.issueIsLoading = false;
|
||||||
|
this.actionAreLoaded = true;
|
||||||
|
this.updateActionsList();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/* When choosing an issue in multiselect, add it in checkboxes (as selected),
|
||||||
remove it from multiselect, and add socialActions concerned
|
remove it from multiselect, and add socialActions concerned
|
||||||
*/
|
*/
|
||||||
addIssueInList(value) {
|
addIssueInList(value) {
|
||||||
//console.log('addIssueInList', value);
|
//console.log('addIssueInList', value);
|
||||||
this.$store.commit("addIssueInList", value);
|
this.$store.commit("addIssueInList", value);
|
||||||
this.$store.commit("removeIssueInOther", value);
|
this.$store.commit("removeIssueInOther", value);
|
||||||
this.$store.dispatch("addIssueSelected", value);
|
this.$store.dispatch("addIssueSelected", value);
|
||||||
this.updateActionsList();
|
this.updateActionsList();
|
||||||
},
|
},
|
||||||
/* Update value for selected issues checkboxes
|
/* Update value for selected issues checkboxes
|
||||||
*/
|
*/
|
||||||
updateIssuesSelected(issues) {
|
updateIssuesSelected(issues) {
|
||||||
//console.log('updateIssuesSelected', issues);
|
//console.log('updateIssuesSelected', issues);
|
||||||
this.$store.dispatch("updateIssuesSelected", issues);
|
this.$store.dispatch("updateIssuesSelected", issues);
|
||||||
this.updateActionsList();
|
this.updateActionsList();
|
||||||
},
|
},
|
||||||
/* Update value for selected actions checkboxes
|
/* Update value for selected actions checkboxes
|
||||||
*/
|
*/
|
||||||
updateActionsSelected(actions) {
|
updateActionsSelected(actions) {
|
||||||
//console.log('updateActionsSelected', actions);
|
//console.log('updateActionsSelected', actions);
|
||||||
this.$store.dispatch("updateActionsSelected", actions);
|
this.$store.dispatch("updateActionsSelected", actions);
|
||||||
},
|
},
|
||||||
/* Add socialActions concerned: after reset, loop on each issue selected
|
/* Add socialActions concerned: after reset, loop on each issue selected
|
||||||
to get social actions concerned
|
to get social actions concerned
|
||||||
*/
|
*/
|
||||||
updateActionsList() {
|
updateActionsList() {
|
||||||
this.resetActionsList();
|
this.resetActionsList();
|
||||||
this.socialIssuesSelected.forEach((item) => {
|
this.socialIssuesSelected.forEach((item) => {
|
||||||
this.actionIsLoading = true;
|
this.actionIsLoading = true;
|
||||||
getSocialActionByIssue(item.id).then(
|
getSocialActionByIssue(item.id).then(
|
||||||
(actions) =>
|
(actions) =>
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
actions.results.forEach((action) => {
|
actions.results.forEach((action) => {
|
||||||
this.$store.commit("addActionInList", action);
|
this.$store.commit("addActionInList", action);
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
this.$store.commit("filterList", "actions");
|
this.$store.commit("filterList", "actions");
|
||||||
|
|
||||||
this.actionIsLoading = false;
|
this.actionIsLoading = false;
|
||||||
this.actionAreLoaded = true;
|
this.actionAreLoaded = true;
|
||||||
resolve();
|
resolve();
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}, this);
|
}, this);
|
||||||
|
},
|
||||||
|
/* Reset socialActions List: flush list and restore selected actions
|
||||||
|
*/
|
||||||
|
resetActionsList() {
|
||||||
|
this.$store.commit("resetActionsList");
|
||||||
|
this.actionAreLoaded = false;
|
||||||
|
this.socialActionsSelected.forEach((item) => {
|
||||||
|
this.$store.commit("addActionInList", item);
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
/* Reset socialActions List: flush list and restore selected actions
|
|
||||||
*/
|
|
||||||
resetActionsList() {
|
|
||||||
this.$store.commit("resetActionsList");
|
|
||||||
this.actionAreLoaded = false;
|
|
||||||
this.socialActionsSelected.forEach((item) => {
|
|
||||||
this.$store.commit("addActionInList", item);
|
|
||||||
}, this);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -278,18 +284,18 @@ export default {
|
|||||||
@import "ChillMainAssets/chill/scss/chill_variables";
|
@import "ChillMainAssets/chill/scss/chill_variables";
|
||||||
|
|
||||||
span.multiselect__single {
|
span.multiselect__single {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#actionsList {
|
#actionsList {
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
margin: 0.5rem;
|
margin: 0.5rem;
|
||||||
background-color: whitesmoke;
|
background-color: whitesmoke;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.badge {
|
span.badge {
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
@include badge_social($social-issue-color);
|
@include badge_social($social-issue-color);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,38 +1,38 @@
|
|||||||
<template>
|
<template>
|
||||||
<span class="inline-choice">
|
<span class="inline-choice">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input
|
<input
|
||||||
class="form-check-input"
|
class="form-check-input"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
v-model="selected"
|
v-model="selected"
|
||||||
name="action"
|
name="action"
|
||||||
:id="action.id"
|
:id="action.id"
|
||||||
:value="action"
|
:value="action"
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label" :for="action.id">
|
<label class="form-check-label" :for="action.id">
|
||||||
<span class="badge bg-light text-dark" :title="action.text">{{
|
<span class="badge bg-light text-dark" :title="action.text">{{
|
||||||
action.text
|
action.text
|
||||||
}}</span>
|
}}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: "CheckSocialAction",
|
name: "CheckSocialAction",
|
||||||
props: ["action", "selection"],
|
props: ["action", "selection"],
|
||||||
emits: ["updateSelected"],
|
emits: ["updateSelected"],
|
||||||
computed: {
|
computed: {
|
||||||
selected: {
|
selected: {
|
||||||
set(value) {
|
set(value) {
|
||||||
this.$emit("updateSelected", value);
|
this.$emit("updateSelected", value);
|
||||||
},
|
},
|
||||||
get() {
|
get() {
|
||||||
return this.selection;
|
return this.selection;
|
||||||
},
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -41,24 +41,25 @@ export default {
|
|||||||
@import "ChillPersonAssets/chill/scss/mixins";
|
@import "ChillPersonAssets/chill/scss/mixins";
|
||||||
@import "ChillMainAssets/chill/scss/chill_variables";
|
@import "ChillMainAssets/chill/scss/chill_variables";
|
||||||
span.badge {
|
span.badge {
|
||||||
@include badge_social($social-action-color);
|
@include badge_social($social-action-color);
|
||||||
font-size: 95%;
|
font-size: 95%;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
line-height: 1.2em;
|
line-height: 1.2em;
|
||||||
&::before {
|
|
||||||
position: absolute;
|
&::before {
|
||||||
left: 11px;
|
position: absolute;
|
||||||
top: 0;
|
left: 11px;
|
||||||
margin: 0 0.3em 0 -0.75em;
|
top: 0;
|
||||||
}
|
margin: 0 0.3em 0 -0.75em;
|
||||||
position: relative;
|
}
|
||||||
padding-left: 1.5em;
|
position: relative;
|
||||||
|
padding-left: 1.5em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,36 +1,38 @@
|
|||||||
<template>
|
<template>
|
||||||
<span class="inline-choice">
|
<span class="inline-choice">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input
|
<input
|
||||||
class="form-check-input"
|
class="form-check-input"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
v-model="selected"
|
v-model="selected"
|
||||||
name="issue"
|
name="issue"
|
||||||
:id="issue.id"
|
:id="issue.id"
|
||||||
:value="issue"
|
:value="issue"
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label" :for="issue.id">
|
<label class="form-check-label" :for="issue.id">
|
||||||
<span class="badge bg-chill-l-gray text-dark">{{ issue.text }}</span>
|
<span class="badge bg-chill-l-gray text-dark">{{
|
||||||
</label>
|
issue.text
|
||||||
</div>
|
}}</span>
|
||||||
</span>
|
</label>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: "CheckSocialIssue",
|
name: "CheckSocialIssue",
|
||||||
props: ["issue", "selection"],
|
props: ["issue", "selection"],
|
||||||
emits: ["updateSelected"],
|
emits: ["updateSelected"],
|
||||||
computed: {
|
computed: {
|
||||||
selected: {
|
selected: {
|
||||||
set(value) {
|
set(value) {
|
||||||
this.$emit("updateSelected", value);
|
this.$emit("updateSelected", value);
|
||||||
},
|
},
|
||||||
get() {
|
get() {
|
||||||
return this.selection;
|
return this.selection;
|
||||||
},
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -39,24 +41,24 @@ export default {
|
|||||||
@import "ChillPersonAssets/chill/scss/mixins";
|
@import "ChillPersonAssets/chill/scss/mixins";
|
||||||
@import "ChillMainAssets/chill/scss/chill_variables";
|
@import "ChillMainAssets/chill/scss/chill_variables";
|
||||||
span.badge {
|
span.badge {
|
||||||
@include badge_social($social-issue-color);
|
@include badge_social($social-issue-color);
|
||||||
font-size: 95%;
|
font-size: 95%;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 11px;
|
left: 11px;
|
||||||
top: 0;
|
top: 0;
|
||||||
margin: 0 0.3em 0 -0.75em;
|
margin: 0 0.3em 0 -0.75em;
|
||||||
}
|
}
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-left: 1.5em;
|
padding-left: 1.5em;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -124,9 +124,9 @@
|
|||||||
{# {{ form(delete_form) }} #}
|
{# {{ form(delete_form) }} #}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ encore_entry_script_tags('mod_pickentity_type') }}
|
{{ vite_entry_script_tags('mod_pickentity_type') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ encore_entry_link_tags('mod_pickentity_type') }}
|
{{ vite_entry_link_tags('mod_pickentity_type') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_async_upload') }}
|
{{ vite_entry_script_tags('mod_async_upload') }}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.addEventListener('DOMContentLoaded', function (e) {
|
window.addEventListener('DOMContentLoaded', function (e) {
|
||||||
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
|
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
|
||||||
@@ -23,12 +23,12 @@
|
|||||||
});
|
});
|
||||||
window.activity = {{ activity_json|json_encode|raw }};
|
window.activity = {{ activity_json|json_encode|raw }};
|
||||||
</script>
|
</script>
|
||||||
{{ encore_entry_script_tags('vue_activity') }}
|
{{ vite_entry_script_tags('vue_activity') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('mod_async_upload') }}
|
{{ vite_entry_link_tags('mod_async_upload') }}
|
||||||
{{ encore_entry_link_tags('vue_activity') }}
|
{{ vite_entry_link_tags('vue_activity') }}
|
||||||
{{ encore_entry_link_tags('page_edit_activity') }}
|
{{ vite_entry_link_tags('page_edit_activity') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ encore_entry_script_tags('mod_async_upload') }}
|
{{ vite_entry_script_tags('mod_async_upload') }}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.addEventListener('DOMContentLoaded', function (e) {
|
window.addEventListener('DOMContentLoaded', function (e) {
|
||||||
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
|
chill.displayAlertWhenLeavingModifiedForm('form[name="{{ edit_form.vars.form.vars.name }}"]',
|
||||||
@@ -38,10 +38,10 @@
|
|||||||
});
|
});
|
||||||
window.activity = {{ activity_json|json_encode|raw }};
|
window.activity = {{ activity_json|json_encode|raw }};
|
||||||
</script>
|
</script>
|
||||||
{{ encore_entry_script_tags('vue_activity') }}
|
{{ vite_entry_script_tags('vue_activity') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ encore_entry_link_tags('mod_async_upload') }}
|
{{ vite_entry_link_tags('mod_async_upload') }}
|
||||||
{{ encore_entry_link_tags('vue_activity') }}
|
{{ vite_entry_link_tags('vue_activity') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -7,14 +7,14 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_notification_toggle_read_status') }}
|
{{ vite_entry_script_tags('mod_notification_toggle_read_status') }}
|
||||||
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
|
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('mod_notification_toggle_read_status') }}
|
{{ vite_entry_link_tags('mod_notification_toggle_read_status') }}
|
||||||
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
|
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -22,14 +22,14 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_notification_toggle_read_status') }}
|
{{ vite_entry_script_tags('mod_notification_toggle_read_status') }}
|
||||||
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
|
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('mod_notification_toggle_read_status') }}
|
{{ vite_entry_link_tags('mod_notification_toggle_read_status') }}
|
||||||
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
|
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -121,9 +121,9 @@
|
|||||||
{{ form_end(form) }}
|
{{ form_end(form) }}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ encore_entry_script_tags('mod_pickentity_type') }}
|
{{ vite_entry_script_tags('mod_pickentity_type') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ encore_entry_link_tags('mod_pickentity_type') }}
|
{{ vite_entry_link_tags('mod_pickentity_type') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -15,16 +15,16 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_async_upload') }}
|
{{ vite_entry_script_tags('mod_async_upload') }}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.activity = {{ activity_json|json_encode|raw }};
|
window.activity = {{ activity_json|json_encode|raw }};
|
||||||
{% if default_location is not null %}window.default_location_id = {{ default_location.id }}{% endif %};
|
{% if default_location is not null %}window.default_location_id = {{ default_location.id }}{% endif %};
|
||||||
</script>
|
</script>
|
||||||
{{ encore_entry_script_tags('vue_activity') }}
|
{{ vite_entry_script_tags('vue_activity') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('mod_async_upload') }}
|
{{ vite_entry_link_tags('mod_async_upload') }}
|
||||||
{{ encore_entry_link_tags('vue_activity') }}
|
{{ vite_entry_link_tags('vue_activity') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ encore_entry_script_tags('mod_async_upload') }}
|
{{ vite_entry_script_tags('mod_async_upload') }}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.addEventListener('DOMContentLoaded', function (e) {
|
window.addEventListener('DOMContentLoaded', function (e) {
|
||||||
chill.displayAlertWhenLeavingUnsubmittedForm('form[name="{{ form.vars.form.vars.name }}"]',
|
chill.displayAlertWhenLeavingUnsubmittedForm('form[name="{{ form.vars.form.vars.name }}"]',
|
||||||
@@ -22,10 +22,10 @@
|
|||||||
});
|
});
|
||||||
window.activity = {{ activity_json|json_encode|raw }};
|
window.activity = {{ activity_json|json_encode|raw }};
|
||||||
</script>
|
</script>
|
||||||
{{ encore_entry_script_tags('vue_activity') }}
|
{{ vite_entry_script_tags('vue_activity') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ encore_entry_link_tags('mod_async_upload') }}
|
{{ vite_entry_link_tags('mod_async_upload') }}
|
||||||
{{ encore_entry_link_tags('vue_activity') }}
|
{{ vite_entry_link_tags('vue_activity') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -6,16 +6,16 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_notification_toggle_read_status') }}
|
{{ vite_entry_script_tags('mod_notification_toggle_read_status') }}
|
||||||
{{ encore_entry_script_tags('mod_async_upload') }}
|
{{ vite_entry_script_tags('mod_async_upload') }}
|
||||||
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
|
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('mod_notification_toggle_read_status') }}
|
{{ vite_entry_link_tags('mod_notification_toggle_read_status') }}
|
||||||
{{ encore_entry_link_tags('mod_async_upload') }}
|
{{ vite_entry_link_tags('mod_async_upload') }}
|
||||||
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
|
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% import '@ChillActivity/ActivityReason/macro.html.twig' as m %}
|
{% import '@ChillActivity/ActivityReason/macro.html.twig' as m %}
|
||||||
|
|||||||
@@ -6,14 +6,14 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_notification_toggle_read_status') }}
|
{{ vite_entry_script_tags('mod_notification_toggle_read_status') }}
|
||||||
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
|
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('mod_notification_toggle_read_status') }}
|
{{ vite_entry_link_tags('mod_notification_toggle_read_status') }}
|
||||||
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
|
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% import '@ChillActivity/ActivityReason/macro.html.twig' as m %}
|
{% import '@ChillActivity/ActivityReason/macro.html.twig' as m %}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
// this file loads all assets from the Chill person bundle
|
|
||||||
module.exports = function (encore, entries) {
|
|
||||||
entries.push(__dirname + "/Resources/public/chill/index.js");
|
|
||||||
|
|
||||||
encore.addAliases({
|
|
||||||
ChillActivityAssets: __dirname + "/Resources/public",
|
|
||||||
});
|
|
||||||
|
|
||||||
encore.addEntry(
|
|
||||||
"page_edit_activity",
|
|
||||||
__dirname + "/Resources/public/page/edit_activity/index.scss",
|
|
||||||
);
|
|
||||||
|
|
||||||
encore.addEntry(
|
|
||||||
"vue_activity",
|
|
||||||
__dirname + "/Resources/public/vuejs/Activity/index.js",
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -39,7 +39,7 @@ final class Version20251118124241 extends AbstractMigration
|
|||||||
$this->addSql("COMMENT ON COLUMN activity_user.by_migration IS 'For backup purpose - can be safely deleted after a while. See migration \\Chill\\Migrations\\Activity\\Version20251118124241'");
|
$this->addSql("COMMENT ON COLUMN activity_user.by_migration IS 'For backup purpose - can be safely deleted after a while. See migration \\Chill\\Migrations\\Activity\\Version20251118124241'");
|
||||||
|
|
||||||
$this->addSql('INSERT INTO activity_user (activity_id, user_id, by_migration)
|
$this->addSql('INSERT INTO activity_user (activity_id, user_id, by_migration)
|
||||||
SELECT id, user_id, true FROM activity
|
SELECT id, user_id, true FROM activity WHERE user_id is not null
|
||||||
ON CONFLICT DO NOTHING');
|
ON CONFLICT DO NOTHING');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
src/Bundle/ChillActivityBundle/vite.config.js
Normal file
14
src/Bundle/ChillActivityBundle/vite.config.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export default {
|
||||||
|
chillBase: [
|
||||||
|
"./src/Bundle/ChillActivityBundle/Resources/public/chill/index.js",
|
||||||
|
],
|
||||||
|
aliases: {
|
||||||
|
ChillActivityAssets: "./src/Bundle/ChillActivityBundle/Resources/public",
|
||||||
|
},
|
||||||
|
inputs: {
|
||||||
|
page_edit_activity:
|
||||||
|
"./src/Bundle/ChillActivityBundle/Resources/public/page/edit_activity/index.scss",
|
||||||
|
vue_activity:
|
||||||
|
"./src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/index.js",
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_pickentity_type') }}
|
{{ vite_entry_script_tags('mod_pickentity_type') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('mod_pickentity_type') }}
|
{{ vite_entry_link_tags('mod_pickentity_type') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
require("./chillbudget.scss");
|
import("./chillbudget.scss");
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
{% block title title %}
|
{% block title title %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ encore_entry_script_tags('page_budget') }}
|
{{ vite_entry_script_tags('page_budget') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ encore_entry_link_tags('page_budget') }}
|
{{ vite_entry_link_tags('page_budget') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
{% block title title %}
|
{% block title title %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ encore_entry_script_tags('page_budget') }}
|
{{ vite_entry_script_tags('page_budget') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ encore_entry_link_tags('page_budget') }}
|
{{ vite_entry_link_tags('page_budget') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
// this file loads all assets from the Chill budget bundle
|
|
||||||
module.exports = function (encore, entries) {
|
|
||||||
encore.addAliases({
|
|
||||||
ChillBudgetAssets: __dirname + "/Resources/public",
|
|
||||||
});
|
|
||||||
|
|
||||||
encore.addEntry("page_budget", __dirname + "/Resources/public/page/index.js");
|
|
||||||
};
|
|
||||||
8
src/Bundle/ChillBudgetBundle/vite.config.js
Normal file
8
src/Bundle/ChillBudgetBundle/vite.config.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export default {
|
||||||
|
aliases: {
|
||||||
|
ChillBudgetAssets: "./src/Bundle/ChillBudgetBundle/Resources/public",
|
||||||
|
},
|
||||||
|
inputs: {
|
||||||
|
page_budget: "./src/Bundle/ChillBudgetBundle/Resources/public/page/index.js",
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1 +1 @@
|
|||||||
require("./scss/calendar.scss");
|
import("./scss/calendar.scss");
|
||||||
|
|||||||
@@ -1,74 +1,76 @@
|
|||||||
import { EventInput } from "@fullcalendar/core";
|
import { EventInput } from "@fullcalendar/core";
|
||||||
import {
|
import {
|
||||||
DateTime,
|
DateTime,
|
||||||
Location,
|
Location,
|
||||||
User,
|
User,
|
||||||
UserAssociatedInterface,
|
UserAssociatedInterface,
|
||||||
} from "../../../ChillMainBundle/Resources/public/types";
|
} from "../../../ChillMainBundle/Resources/public/types";
|
||||||
import { Person } from "../../../ChillPersonBundle/Resources/public/types";
|
import { Person } from "../../../ChillPersonBundle/Resources/public/types";
|
||||||
|
|
||||||
export interface CalendarRange {
|
export interface CalendarRange {
|
||||||
id: number;
|
id: number;
|
||||||
endDate: DateTime;
|
endDate: DateTime;
|
||||||
startDate: DateTime;
|
startDate: DateTime;
|
||||||
user: User;
|
user: User;
|
||||||
location: Location;
|
location: Location;
|
||||||
createdAt: DateTime;
|
createdAt: DateTime;
|
||||||
createdBy: User;
|
createdBy: User;
|
||||||
updatedAt: DateTime;
|
updatedAt: DateTime;
|
||||||
updatedBy: User;
|
updatedBy: User;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CalendarRangeCreate {
|
export interface CalendarRangeCreate {
|
||||||
user: UserAssociatedInterface;
|
user: UserAssociatedInterface;
|
||||||
startDate: DateTime;
|
startDate: DateTime;
|
||||||
endDate: DateTime;
|
endDate: DateTime;
|
||||||
location: Location;
|
location: Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CalendarRangeEdit {
|
export interface CalendarRangeEdit {
|
||||||
startDate?: DateTime;
|
startDate?: DateTime;
|
||||||
endDate?: DateTime;
|
endDate?: DateTime;
|
||||||
location?: Location;
|
location?: Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Calendar {
|
export interface Calendar {
|
||||||
id: number;
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CalendarLight {
|
export interface CalendarLight {
|
||||||
id: number;
|
id: number;
|
||||||
endDate: DateTime;
|
endDate: DateTime;
|
||||||
startDate: DateTime;
|
startDate: DateTime;
|
||||||
mainUser: User;
|
mainUser: User;
|
||||||
persons: Person[];
|
persons: Person[];
|
||||||
status: "valid" | "moved" | "canceled";
|
status: "valid" | "moved" | "canceled";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CalendarRemote {
|
export interface CalendarRemote {
|
||||||
id: number;
|
id: number;
|
||||||
endDate: DateTime;
|
endDate: DateTime;
|
||||||
startDate: DateTime;
|
startDate: DateTime;
|
||||||
title: string;
|
title: string;
|
||||||
isAllDay: boolean;
|
isAllDay: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EventInputCalendarRange = EventInput & {
|
export type EventInputCalendarRange = EventInput & {
|
||||||
id: string;
|
id: string;
|
||||||
userId: number;
|
userId: number;
|
||||||
userLabel: string;
|
userLabel: string;
|
||||||
calendarRangeId: number;
|
calendarRangeId: number;
|
||||||
locationId: number;
|
locationId: number;
|
||||||
locationName: string;
|
locationName: string;
|
||||||
start: string;
|
start: string;
|
||||||
end: string;
|
end: string;
|
||||||
is: "range";
|
is: "range";
|
||||||
};
|
};
|
||||||
|
|
||||||
export function isEventInputCalendarRange(
|
export function isEventInputCalendarRange(
|
||||||
toBeDetermined: EventInputCalendarRange | EventInput,
|
toBeDetermined: EventInputCalendarRange | EventInput,
|
||||||
): toBeDetermined is EventInputCalendarRange {
|
): toBeDetermined is EventInputCalendarRange {
|
||||||
return typeof toBeDetermined.is === "string" && toBeDetermined.is === "range";
|
return (
|
||||||
|
typeof toBeDetermined.is === "string" && toBeDetermined.is === "range"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export {};
|
export {};
|
||||||
|
|||||||
@@ -1,148 +1,166 @@
|
|||||||
<template>
|
<template>
|
||||||
<teleport to="#mainUser">
|
<teleport to="#mainUser">
|
||||||
<h2 class="chill-red">Utilisateur principal</h2>
|
<h2 class="chill-red">Utilisateur principal</h2>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<div v-if="null !== this.$store.getters.getMainUser">
|
<div v-if="null !== this.$store.getters.getMainUser">
|
||||||
<calendar-active :user="this.$store.getters.getMainUser" />
|
<calendar-active :user="this.$store.getters.getMainUser" />
|
||||||
|
</div>
|
||||||
|
<pick-entity
|
||||||
|
:multiple="false"
|
||||||
|
:types="['user']"
|
||||||
|
:uniqid="'main_user_calendar'"
|
||||||
|
:picked="
|
||||||
|
null !== this.$store.getters.getMainUser
|
||||||
|
? [this.$store.getters.getMainUser]
|
||||||
|
: []
|
||||||
|
"
|
||||||
|
:removable-if-set="false"
|
||||||
|
:display-picked="false"
|
||||||
|
:suggested="this.suggestedUsers"
|
||||||
|
:label="'main_user'"
|
||||||
|
@add-new-entity="setMainUser"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<pick-entity
|
</teleport>
|
||||||
:multiple="false"
|
|
||||||
:types="['user']"
|
|
||||||
:uniqid="'main_user_calendar'"
|
|
||||||
:picked="
|
|
||||||
null !== this.$store.getters.getMainUser
|
|
||||||
? [this.$store.getters.getMainUser]
|
|
||||||
: []
|
|
||||||
"
|
|
||||||
:removable-if-set="false"
|
|
||||||
:display-picked="false"
|
|
||||||
:suggested="this.suggestedUsers"
|
|
||||||
:label="'main_user'"
|
|
||||||
@add-new-entity="setMainUser"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</teleport>
|
|
||||||
|
|
||||||
<concerned-groups />
|
<concerned-groups />
|
||||||
|
|
||||||
<teleport to="#schedule">
|
<teleport to="#schedule">
|
||||||
<div class="row mb-3" v-if="activity.startDate !== null">
|
<div class="row mb-3" v-if="activity.startDate !== null">
|
||||||
<label class="col-form-label col-sm-4">Date</label>
|
<label class="col-form-label col-sm-4">Date</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
{{ $d(activity.startDate, "long") }} -
|
{{ $d(activity.startDate, "long") }} -
|
||||||
{{ $d(activity.endDate, "hoursOnly") }}
|
{{ $d(activity.endDate, "hoursOnly") }}
|
||||||
<span v-if="activity.calendarRange === null"
|
<span v-if="activity.calendarRange === null"
|
||||||
>(Pas de plage de disponibilité sélectionnée)</span
|
>(Pas de plage de disponibilité sélectionnée)</span
|
||||||
|
>
|
||||||
|
<span v-else>(Une plage de disponibilité sélectionnée)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</teleport>
|
||||||
|
|
||||||
|
<location />
|
||||||
|
|
||||||
|
<teleport to="#fullCalendar">
|
||||||
|
<div class="calendar-actives">
|
||||||
|
<template v-for="u in getActiveUsers" :key="u.id">
|
||||||
|
<calendar-active
|
||||||
|
:user="u"
|
||||||
|
:invite="this.$store.getters.getInviteForUser(u)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="display-options row justify-content-between"
|
||||||
|
style="margin-top: 1rem"
|
||||||
>
|
>
|
||||||
<span v-else>(Une plage de disponibilité sélectionnée)</span>
|
<div class="col-sm-9 col-xs-12">
|
||||||
</div>
|
<div class="input-group mb-3">
|
||||||
</div>
|
<label class="input-group-text" for="slotDuration"
|
||||||
</teleport>
|
>Durée des créneaux</label
|
||||||
|
>
|
||||||
<location />
|
<select
|
||||||
|
v-model="slotDuration"
|
||||||
<teleport to="#fullCalendar">
|
id="slotDuration"
|
||||||
<div class="calendar-actives">
|
class="form-select"
|
||||||
<template v-for="u in getActiveUsers" :key="u.id">
|
>
|
||||||
<calendar-active
|
<option value="00:05:00">5 minutes</option>
|
||||||
:user="u"
|
<option value="00:10:00">10 minutes</option>
|
||||||
:invite="this.$store.getters.getInviteForUser(u)"
|
<option value="00:15:00">15 minutes</option>
|
||||||
/>
|
<option value="00:30:00">30 minutes</option>
|
||||||
</template>
|
<option value="00:45:00">45 minutes</option>
|
||||||
</div>
|
<option value="00:60:00">60 minutes</option>
|
||||||
<div
|
</select>
|
||||||
class="display-options row justify-content-between"
|
<label class="input-group-text" for="slotMinTime">De</label>
|
||||||
style="margin-top: 1rem"
|
<select
|
||||||
>
|
v-model="slotMinTime"
|
||||||
<div class="col-sm-9 col-xs-12">
|
id="slotMinTime"
|
||||||
<div class="input-group mb-3">
|
class="form-select"
|
||||||
<label class="input-group-text" for="slotDuration"
|
>
|
||||||
>Durée des créneaux</label
|
<option value="00:00:00">0h</option>
|
||||||
>
|
<option value="01:00:00">1h</option>
|
||||||
<select v-model="slotDuration" id="slotDuration" class="form-select">
|
<option value="02:00:00">2h</option>
|
||||||
<option value="00:05:00">5 minutes</option>
|
<option value="03:00:00">3h</option>
|
||||||
<option value="00:10:00">10 minutes</option>
|
<option value="04:00:00">4h</option>
|
||||||
<option value="00:15:00">15 minutes</option>
|
<option value="05:00:00">5h</option>
|
||||||
<option value="00:30:00">30 minutes</option>
|
<option value="06:00:00">6h</option>
|
||||||
<option value="00:45:00">45 minutes</option>
|
<option value="07:00:00">7h</option>
|
||||||
<option value="00:60:00">60 minutes</option>
|
<option value="08:00:00">8h</option>
|
||||||
</select>
|
<option value="09:00:00">9h</option>
|
||||||
<label class="input-group-text" for="slotMinTime">De</label>
|
<option value="10:00:00">10h</option>
|
||||||
<select v-model="slotMinTime" id="slotMinTime" class="form-select">
|
<option value="11:00:00">11h</option>
|
||||||
<option value="00:00:00">0h</option>
|
<option value="12:00:00">12h</option>
|
||||||
<option value="01:00:00">1h</option>
|
</select>
|
||||||
<option value="02:00:00">2h</option>
|
<label class="input-group-text" for="slotMaxTime">À</label>
|
||||||
<option value="03:00:00">3h</option>
|
<select
|
||||||
<option value="04:00:00">4h</option>
|
v-model="slotMaxTime"
|
||||||
<option value="05:00:00">5h</option>
|
id="slotMaxTime"
|
||||||
<option value="06:00:00">6h</option>
|
class="form-select"
|
||||||
<option value="07:00:00">7h</option>
|
>
|
||||||
<option value="08:00:00">8h</option>
|
<option value="12:00:00">12h</option>
|
||||||
<option value="09:00:00">9h</option>
|
<option value="13:00:00">13h</option>
|
||||||
<option value="10:00:00">10h</option>
|
<option value="14:00:00">14h</option>
|
||||||
<option value="11:00:00">11h</option>
|
<option value="15:00:00">15h</option>
|
||||||
<option value="12:00:00">12h</option>
|
<option value="16:00:00">16h</option>
|
||||||
</select>
|
<option value="17:00:00">17h</option>
|
||||||
<label class="input-group-text" for="slotMaxTime">À</label>
|
<option value="18:00:00">18h</option>
|
||||||
<select v-model="slotMaxTime" id="slotMaxTime" class="form-select">
|
<option value="19:00:00">19h</option>
|
||||||
<option value="12:00:00">12h</option>
|
<option value="20:00:00">20h</option>
|
||||||
<option value="13:00:00">13h</option>
|
<option value="21:00:00">21h</option>
|
||||||
<option value="14:00:00">14h</option>
|
<option value="22:00:00">22h</option>
|
||||||
<option value="15:00:00">15h</option>
|
<option value="23:00:00">23h</option>
|
||||||
<option value="16:00:00">16h</option>
|
<option value="23:59:59">24h</option>
|
||||||
<option value="17:00:00">17h</option>
|
</select>
|
||||||
<option value="18:00:00">18h</option>
|
</div>
|
||||||
<option value="19:00:00">19h</option>
|
</div>
|
||||||
<option value="20:00:00">20h</option>
|
<div class="col-sm-3 col-xs-12">
|
||||||
<option value="21:00:00">21h</option>
|
<div class="float-end">
|
||||||
<option value="22:00:00">22h</option>
|
<div class="form-check input-group">
|
||||||
<option value="23:00:00">23h</option>
|
<span class="input-group-text">
|
||||||
<option value="23:59:59">24h</option>
|
<input
|
||||||
</select>
|
id="showHideWE"
|
||||||
|
class="mt-0"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="hideWeekends"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<label
|
||||||
|
for="showHideWE"
|
||||||
|
class="form-check-label input-group-text"
|
||||||
|
>Week-ends</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<FullCalendar ref="fullCalendar" :options="calendarOptions">
|
||||||
<div class="col-sm-3 col-xs-12">
|
<template #eventContent="arg">
|
||||||
<div class="float-end">
|
<span>
|
||||||
<div class="form-check input-group">
|
<b v-if="arg.event.extendedProps.is === 'remote'">{{
|
||||||
<span class="input-group-text">
|
arg.event.title
|
||||||
<input
|
}}</b>
|
||||||
id="showHideWE"
|
<b v-else-if="arg.event.extendedProps.is === 'range'"
|
||||||
class="mt-0"
|
>{{ arg.timeText }}
|
||||||
type="checkbox"
|
{{ arg.event.extendedProps.locationName }}
|
||||||
v-model="hideWeekends"
|
<small>{{
|
||||||
/>
|
arg.event.extendedProps.userLabel
|
||||||
</span>
|
}}</small></b
|
||||||
<label for="showHideWE" class="form-check-label input-group-text"
|
>
|
||||||
>Week-ends</label
|
<b v-else-if="arg.event.extendedProps.is === 'current'"
|
||||||
>
|
>{{ arg.timeText }} {{ $t("current_selected") }}
|
||||||
</div>
|
</b>
|
||||||
</div>
|
<b v-else-if="arg.event.extendedProps.is === 'local'">{{
|
||||||
</div>
|
arg.event.title
|
||||||
</div>
|
}}</b>
|
||||||
<FullCalendar ref="fullCalendar" :options="calendarOptions">
|
<b v-else
|
||||||
<template #eventContent="arg">
|
>{{ arg.timeText }} {{ $t("current_selected") }}
|
||||||
<span>
|
</b>
|
||||||
<b v-if="arg.event.extendedProps.is === 'remote'">{{
|
</span>
|
||||||
arg.event.title
|
</template>
|
||||||
}}</b>
|
</FullCalendar>
|
||||||
<b v-else-if="arg.event.extendedProps.is === 'range'"
|
</teleport>
|
||||||
>{{ arg.timeText }}
|
|
||||||
{{ arg.event.extendedProps.locationName }}
|
|
||||||
<small>{{ arg.event.extendedProps.userLabel }}</small></b
|
|
||||||
>
|
|
||||||
<b v-else-if="arg.event.extendedProps.is === 'current'"
|
|
||||||
>{{ arg.timeText }} {{ $t("current_selected") }}
|
|
||||||
</b>
|
|
||||||
<b v-else-if="arg.event.extendedProps.is === 'local'">{{
|
|
||||||
arg.event.title
|
|
||||||
}}</b>
|
|
||||||
<b v-else>{{ arg.timeText }} {{ $t("current_selected") }} </b>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</FullCalendar>
|
|
||||||
</teleport>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -159,210 +177,219 @@ import PickEntity from "ChillMainAssets/vuejs/PickEntity/PickEntity.vue";
|
|||||||
import { mapGetters, mapState } from "vuex";
|
import { mapGetters, mapState } from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
components: {
|
components: {
|
||||||
ConcernedGroups,
|
ConcernedGroups,
|
||||||
Location,
|
Location,
|
||||||
FullCalendar,
|
FullCalendar,
|
||||||
CalendarActive,
|
CalendarActive,
|
||||||
PickEntity,
|
PickEntity,
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
errorMsg: [],
|
|
||||||
showMyCalendar: false,
|
|
||||||
slotDuration: "00:05:00",
|
|
||||||
slotMinTime: "09:00:00",
|
|
||||||
slotMaxTime: "18:00:00",
|
|
||||||
hideWeekEnds: true,
|
|
||||||
previousUser: [],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapGetters(["getMainUser"]),
|
|
||||||
...mapState(["activity"]),
|
|
||||||
events() {
|
|
||||||
return this.$store.getters.getEventSources;
|
|
||||||
},
|
},
|
||||||
calendarOptions() {
|
data() {
|
||||||
return {
|
return {
|
||||||
locale: frLocale,
|
errorMsg: [],
|
||||||
plugins: [
|
showMyCalendar: false,
|
||||||
dayGridPlugin,
|
slotDuration: "00:05:00",
|
||||||
interactionPlugin,
|
slotMinTime: "09:00:00",
|
||||||
timeGridPlugin,
|
slotMaxTime: "18:00:00",
|
||||||
dayGridPlugin,
|
hideWeekEnds: true,
|
||||||
listPlugin,
|
previousUser: [],
|
||||||
],
|
};
|
||||||
initialView: "timeGridWeek",
|
},
|
||||||
initialDate: this.$store.getters.getInitialDate,
|
computed: {
|
||||||
eventSources: this.events,
|
...mapGetters(["getMainUser"]),
|
||||||
selectable: true,
|
...mapState(["activity"]),
|
||||||
slotMinTime: this.slotMinTime,
|
events() {
|
||||||
slotMaxTime: this.slotMaxTime,
|
return this.$store.getters.getEventSources;
|
||||||
scrollTimeReset: false,
|
|
||||||
datesSet: this.onDatesSet,
|
|
||||||
select: this.onDateSelect,
|
|
||||||
eventChange: this.onEventChange,
|
|
||||||
eventClick: this.onEventClick,
|
|
||||||
selectMirror: true,
|
|
||||||
editable: true,
|
|
||||||
weekends: !this.hideWeekEnds,
|
|
||||||
headerToolbar: {
|
|
||||||
left: "prev,next today",
|
|
||||||
center: "title",
|
|
||||||
right: "timeGridWeek,timeGridDay,listWeek",
|
|
||||||
},
|
},
|
||||||
views: {
|
calendarOptions() {
|
||||||
timeGrid: {
|
return {
|
||||||
slotEventOverlap: false,
|
locale: frLocale,
|
||||||
slotDuration: this.slotDuration,
|
plugins: [
|
||||||
},
|
dayGridPlugin,
|
||||||
|
interactionPlugin,
|
||||||
|
timeGridPlugin,
|
||||||
|
dayGridPlugin,
|
||||||
|
listPlugin,
|
||||||
|
],
|
||||||
|
initialView: "timeGridWeek",
|
||||||
|
initialDate: this.$store.getters.getInitialDate,
|
||||||
|
eventSources: this.events,
|
||||||
|
selectable: true,
|
||||||
|
slotMinTime: this.slotMinTime,
|
||||||
|
slotMaxTime: this.slotMaxTime,
|
||||||
|
scrollTimeReset: false,
|
||||||
|
datesSet: this.onDatesSet,
|
||||||
|
select: this.onDateSelect,
|
||||||
|
eventChange: this.onEventChange,
|
||||||
|
eventClick: this.onEventClick,
|
||||||
|
selectMirror: true,
|
||||||
|
editable: true,
|
||||||
|
weekends: !this.hideWeekEnds,
|
||||||
|
headerToolbar: {
|
||||||
|
left: "prev,next today",
|
||||||
|
center: "title",
|
||||||
|
right: "timeGridWeek,timeGridDay,listWeek",
|
||||||
|
},
|
||||||
|
views: {
|
||||||
|
timeGrid: {
|
||||||
|
slotEventOverlap: false,
|
||||||
|
slotDuration: this.slotDuration,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
getActiveUsers() {
|
||||||
|
const users = [];
|
||||||
|
for (const id of this.$store.state.currentView.users.keys()) {
|
||||||
|
users.push(this.$store.getters.getUserDataById(id).user);
|
||||||
|
}
|
||||||
|
return users;
|
||||||
|
},
|
||||||
|
suggestedUsers() {
|
||||||
|
const suggested = [];
|
||||||
|
|
||||||
|
this.$data.previousUser.forEach((u) => {
|
||||||
|
if (u.id !== this.$store.getters.getMainUser.id) {
|
||||||
|
suggested.push(u);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return suggested;
|
||||||
},
|
},
|
||||||
};
|
|
||||||
},
|
},
|
||||||
getActiveUsers() {
|
methods: {
|
||||||
const users = [];
|
setMainUser({ entity }) {
|
||||||
for (const id of this.$store.state.currentView.users.keys()) {
|
const user = entity;
|
||||||
users.push(this.$store.getters.getUserDataById(id).user);
|
console.log("setMainUser APP", entity);
|
||||||
}
|
|
||||||
return users;
|
if (
|
||||||
|
user.id !== this.$store.getters.getMainUser &&
|
||||||
|
(this.$store.state.activity.calendarRange !== null ||
|
||||||
|
this.$store.state.activity.startDate !== null ||
|
||||||
|
this.$store.state.activity.endDate !== null)
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!window.confirm(
|
||||||
|
this.$t("change_main_user_will_reset_event_data"),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the previous user, if any, in the previous user list (in use for suggestion)
|
||||||
|
if (null !== this.$store.getters.getMainUser) {
|
||||||
|
const suggestedUids = new Set(
|
||||||
|
this.$data.previousUser.map((u) => u.id),
|
||||||
|
);
|
||||||
|
if (!suggestedUids.has(this.$store.getters.getMainUser.id)) {
|
||||||
|
this.$data.previousUser.push(
|
||||||
|
this.$store.getters.getMainUser,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$store.dispatch("setMainUser", user);
|
||||||
|
this.$store.commit("showUserOnCalendar", {
|
||||||
|
user,
|
||||||
|
ranges: true,
|
||||||
|
remotes: true,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
removeMainUser(user) {
|
||||||
|
console.log("removeMainUser APP", user);
|
||||||
|
|
||||||
|
window.alert(this.$t("main_user_is_mandatory"));
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
onDatesSet(event) {
|
||||||
|
console.log("onDatesSet", event);
|
||||||
|
this.$store.dispatch("setCurrentDatesView", {
|
||||||
|
start: event.start,
|
||||||
|
end: event.end,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onDateSelect(payload) {
|
||||||
|
console.log("onDateSelect", payload);
|
||||||
|
|
||||||
|
// show an alert if changing mainUser
|
||||||
|
if (
|
||||||
|
(this.$store.getters.getMainUser !== null &&
|
||||||
|
this.$store.state.me.id !==
|
||||||
|
this.$store.getters.getMainUser.id) ||
|
||||||
|
this.$store.getters.getMainUser === null
|
||||||
|
) {
|
||||||
|
if (!window.confirm(this.$t("will_change_main_user_for_me"))) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
this.$store.commit("showUserOnCalendar", {
|
||||||
|
user: this.$store.state.me,
|
||||||
|
remotes: true,
|
||||||
|
ranges: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$store.dispatch("setEventTimes", {
|
||||||
|
start: payload.start,
|
||||||
|
end: payload.end,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onEventChange(payload) {
|
||||||
|
console.log("onEventChange", payload);
|
||||||
|
if (this.$store.state.activity.calendarRange !== null) {
|
||||||
|
throw new Error(
|
||||||
|
"not allowed to edit a calendar associated with a calendar range",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.$store.dispatch("setEventTimes", {
|
||||||
|
start: payload.event.start,
|
||||||
|
end: payload.event.end,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onEventClick(payload) {
|
||||||
|
if (payload.event.extendedProps.is !== "range") {
|
||||||
|
// do nothing when clicking on remote
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// show an alert if changing mainUser
|
||||||
|
if (
|
||||||
|
this.$store.getters.getMainUser !== null &&
|
||||||
|
payload.event.extendedProps.userId !==
|
||||||
|
this.$store.getters.getMainUser.id
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!window.confirm(
|
||||||
|
this.$t("this_calendar_range_will_change_main_user"),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$store.dispatch("associateCalendarToRange", {
|
||||||
|
range: payload.event,
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
suggestedUsers() {
|
|
||||||
const suggested = [];
|
|
||||||
|
|
||||||
this.$data.previousUser.forEach((u) => {
|
|
||||||
if (u.id !== this.$store.getters.getMainUser.id) {
|
|
||||||
suggested.push(u);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return suggested;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
setMainUser({ entity }) {
|
|
||||||
const user = entity;
|
|
||||||
console.log("setMainUser APP", entity);
|
|
||||||
|
|
||||||
if (
|
|
||||||
user.id !== this.$store.getters.getMainUser &&
|
|
||||||
(this.$store.state.activity.calendarRange !== null ||
|
|
||||||
this.$store.state.activity.startDate !== null ||
|
|
||||||
this.$store.state.activity.endDate !== null)
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
!window.confirm(this.$t("change_main_user_will_reset_event_data"))
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the previous user, if any, in the previous user list (in use for suggestion)
|
|
||||||
if (null !== this.$store.getters.getMainUser) {
|
|
||||||
const suggestedUids = new Set(this.$data.previousUser.map((u) => u.id));
|
|
||||||
if (!suggestedUids.has(this.$store.getters.getMainUser.id)) {
|
|
||||||
this.$data.previousUser.push(this.$store.getters.getMainUser);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$store.dispatch("setMainUser", user);
|
|
||||||
this.$store.commit("showUserOnCalendar", {
|
|
||||||
user,
|
|
||||||
ranges: true,
|
|
||||||
remotes: true,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
removeMainUser(user) {
|
|
||||||
console.log("removeMainUser APP", user);
|
|
||||||
|
|
||||||
window.alert(this.$t("main_user_is_mandatory"));
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
onDatesSet(event) {
|
|
||||||
console.log("onDatesSet", event);
|
|
||||||
this.$store.dispatch("setCurrentDatesView", {
|
|
||||||
start: event.start,
|
|
||||||
end: event.end,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onDateSelect(payload) {
|
|
||||||
console.log("onDateSelect", payload);
|
|
||||||
|
|
||||||
// show an alert if changing mainUser
|
|
||||||
if (
|
|
||||||
(this.$store.getters.getMainUser !== null &&
|
|
||||||
this.$store.state.me.id !== this.$store.getters.getMainUser.id) ||
|
|
||||||
this.$store.getters.getMainUser === null
|
|
||||||
) {
|
|
||||||
if (!window.confirm(this.$t("will_change_main_user_for_me"))) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
this.$store.commit("showUserOnCalendar", {
|
|
||||||
user: this.$store.state.me,
|
|
||||||
remotes: true,
|
|
||||||
ranges: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$store.dispatch("setEventTimes", {
|
|
||||||
start: payload.start,
|
|
||||||
end: payload.end,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onEventChange(payload) {
|
|
||||||
console.log("onEventChange", payload);
|
|
||||||
if (this.$store.state.activity.calendarRange !== null) {
|
|
||||||
throw new Error(
|
|
||||||
"not allowed to edit a calendar associated with a calendar range",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.$store.dispatch("setEventTimes", {
|
|
||||||
start: payload.event.start,
|
|
||||||
end: payload.event.end,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onEventClick(payload) {
|
|
||||||
if (payload.event.extendedProps.is !== "range") {
|
|
||||||
// do nothing when clicking on remote
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// show an alert if changing mainUser
|
|
||||||
if (
|
|
||||||
this.$store.getters.getMainUser !== null &&
|
|
||||||
payload.event.extendedProps.userId !==
|
|
||||||
this.$store.getters.getMainUser.id
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
!window.confirm(this.$t("this_calendar_range_will_change_main_user"))
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$store.dispatch("associateCalendarToRange", {
|
|
||||||
range: payload.event,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.calendar-actives {
|
.calendar-actives {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.display-options {
|
.display-options {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for events which are range */
|
/* for events which are range */
|
||||||
.fc-event.isrange {
|
.fc-event.isrange {
|
||||||
border-width: 3px;
|
border-width: 3px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,105 +1,119 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :style="style" class="calendar-active">
|
<div :style="style" class="calendar-active">
|
||||||
<span class="badge-user">
|
<span class="badge-user">
|
||||||
{{ user.text }}
|
{{ user.text }}
|
||||||
<template v-if="invite !== null">
|
<template v-if="invite !== null">
|
||||||
<i v-if="invite.status === 'accepted'" class="fa fa-check" />
|
<i v-if="invite.status === 'accepted'" class="fa fa-check" />
|
||||||
<i 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"
|
||||||
<span v-else="">{{ invite.status }}</span>
|
/>
|
||||||
</template>
|
<i
|
||||||
</span>
|
v-else-if="invite.status === 'pending'"
|
||||||
<span class="form-check-inline form-switch">
|
class="fa fa-question-o"
|
||||||
<input
|
/>
|
||||||
class="form-check-input"
|
<i
|
||||||
type="checkbox"
|
v-else-if="invite.status === 'tentative'"
|
||||||
id="flexSwitchCheckDefault"
|
class="fa fa-question"
|
||||||
v-model="rangeShow"
|
/>
|
||||||
/>
|
<span v-else="">{{ invite.status }}</span>
|
||||||
<label
|
</template>
|
||||||
class="form-check-label"
|
</span>
|
||||||
for="flexSwitchCheckDefault"
|
<span class="form-check-inline form-switch">
|
||||||
title="Disponibilités"
|
<input
|
||||||
><i class="fa fa-calendar-check-o"
|
class="form-check-input"
|
||||||
/></label>
|
type="checkbox"
|
||||||
</span>
|
id="flexSwitchCheckDefault"
|
||||||
<span class="form-check-inline form-switch">
|
v-model="rangeShow"
|
||||||
<input
|
/>
|
||||||
class="form-check-input"
|
<label
|
||||||
type="checkbox"
|
class="form-check-label"
|
||||||
id="flexSwitchCheckDefault"
|
for="flexSwitchCheckDefault"
|
||||||
v-model="remoteShow"
|
title="Disponibilités"
|
||||||
/>
|
><i class="fa fa-calendar-check-o"
|
||||||
<label
|
/></label>
|
||||||
class="form-check-label"
|
</span>
|
||||||
for="flexSwitchCheckDefault"
|
<span class="form-check-inline form-switch">
|
||||||
title="Agenda"
|
<input
|
||||||
><i class="fa fa-calendar"
|
class="form-check-input"
|
||||||
/></label>
|
type="checkbox"
|
||||||
</span>
|
id="flexSwitchCheckDefault"
|
||||||
</div>
|
v-model="remoteShow"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
class="form-check-label"
|
||||||
|
for="flexSwitchCheckDefault"
|
||||||
|
title="Agenda"
|
||||||
|
><i class="fa fa-calendar"
|
||||||
|
/></label>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from "vuex";
|
import { mapGetters } from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "CalendarActive",
|
name: "CalendarActive",
|
||||||
props: {
|
props: {
|
||||||
user: {
|
user: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
|
},
|
||||||
|
invite: {
|
||||||
|
type: Object,
|
||||||
|
required: false,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
invite: {
|
computed: {
|
||||||
type: Object,
|
style() {
|
||||||
required: false,
|
return {
|
||||||
default: null,
|
backgroundColor: this.$store.getters.getUserData(this.user)
|
||||||
|
.mainColor,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
rangeShow: {
|
||||||
|
set(value) {
|
||||||
|
this.$store.commit("showUserOnCalendar", {
|
||||||
|
user: this.user,
|
||||||
|
ranges: value,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.isRangeShownOnCalendarForUser(
|
||||||
|
this.user,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
remoteShow: {
|
||||||
|
set(value) {
|
||||||
|
this.$store.commit("showUserOnCalendar", {
|
||||||
|
user: this.user,
|
||||||
|
remotes: value,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
get() {
|
||||||
|
return this.$store.getters.isRemoteShownOnCalendarForUser(
|
||||||
|
this.user,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
style() {
|
|
||||||
return {
|
|
||||||
backgroundColor: this.$store.getters.getUserData(this.user).mainColor,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
rangeShow: {
|
|
||||||
set(value) {
|
|
||||||
this.$store.commit("showUserOnCalendar", {
|
|
||||||
user: this.user,
|
|
||||||
ranges: value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
get() {
|
|
||||||
return this.$store.getters.isRangeShownOnCalendarForUser(this.user);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
remoteShow: {
|
|
||||||
set(value) {
|
|
||||||
this.$store.commit("showUserOnCalendar", {
|
|
||||||
user: this.user,
|
|
||||||
remotes: value,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
get() {
|
|
||||||
return this.$store.getters.isRemoteShownOnCalendarForUser(this.user);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.calendar-active {
|
.calendar-active {
|
||||||
margin: 0 0.25rem 0.25rem 0;
|
margin: 0 0.25rem 0.25rem 0;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
|
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
|
|
||||||
color: var(--bs-blue);
|
color: var(--bs-blue);
|
||||||
|
|
||||||
& > .badge-user {
|
& > .badge-user {
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -14,37 +14,37 @@ export { whoami } from "../../../../../ChillMainBundle/Resources/public/lib/api/
|
|||||||
* @return Promise
|
* @return Promise
|
||||||
*/
|
*/
|
||||||
export const fetchCalendarRangeForUser = (
|
export const fetchCalendarRangeForUser = (
|
||||||
user: User,
|
user: User,
|
||||||
start: Date,
|
start: Date,
|
||||||
end: Date,
|
end: Date,
|
||||||
): Promise<CalendarRange[]> => {
|
): Promise<CalendarRange[]> => {
|
||||||
const uri = `/api/1.0/calendar/calendar-range-available/${user.id}.json`;
|
const uri = `/api/1.0/calendar/calendar-range-available/${user.id}.json`;
|
||||||
const dateFrom = datetimeToISO(start);
|
const dateFrom = datetimeToISO(start);
|
||||||
const dateTo = datetimeToISO(end);
|
const dateTo = datetimeToISO(end);
|
||||||
|
|
||||||
return fetchResults<CalendarRange>(uri, { dateFrom, dateTo });
|
return fetchResults<CalendarRange>(uri, { dateFrom, dateTo });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchCalendarRemoteForUser = (
|
export const fetchCalendarRemoteForUser = (
|
||||||
user: User,
|
user: User,
|
||||||
start: Date,
|
start: Date,
|
||||||
end: Date,
|
end: Date,
|
||||||
): Promise<CalendarRemote[]> => {
|
): Promise<CalendarRemote[]> => {
|
||||||
const uri = `/api/1.0/calendar/proxy/calendar/by-user/${user.id}/events`;
|
const uri = `/api/1.0/calendar/proxy/calendar/by-user/${user.id}/events`;
|
||||||
const dateFrom = datetimeToISO(start);
|
const dateFrom = datetimeToISO(start);
|
||||||
const dateTo = datetimeToISO(end);
|
const dateTo = datetimeToISO(end);
|
||||||
|
|
||||||
return fetchResults<CalendarRemote>(uri, { dateFrom, dateTo });
|
return fetchResults<CalendarRemote>(uri, { dateFrom, dateTo });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchCalendarLocalForUser = (
|
export const fetchCalendarLocalForUser = (
|
||||||
user: User,
|
user: User,
|
||||||
start: Date,
|
start: Date,
|
||||||
end: Date,
|
end: Date,
|
||||||
): Promise<CalendarLight[]> => {
|
): Promise<CalendarLight[]> => {
|
||||||
const uri = `/api/1.0/calendar/calendar/by-user/${user.id}.json`;
|
const uri = `/api/1.0/calendar/calendar/by-user/${user.id}.json`;
|
||||||
const dateFrom = datetimeToISO(start);
|
const dateFrom = datetimeToISO(start);
|
||||||
const dateTo = datetimeToISO(end);
|
const dateTo = datetimeToISO(end);
|
||||||
|
|
||||||
return fetchResults<CalendarLight>(uri, { dateFrom, dateTo });
|
return fetchResults<CalendarLight>(uri, { dateFrom, dateTo });
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
const COLORS = [
|
const COLORS = [
|
||||||
/* from https://colorbrewer2.org/#type=qualitative&scheme=Set3&n=12 */
|
/* from https://colorbrewer2.org/#type=qualitative&scheme=Set3&n=12 */
|
||||||
"#8dd3c7",
|
"#8dd3c7",
|
||||||
"#ffffb3",
|
"#ffffb3",
|
||||||
"#bebada",
|
"#bebada",
|
||||||
"#fb8072",
|
"#fb8072",
|
||||||
"#80b1d3",
|
"#80b1d3",
|
||||||
"#fdb462",
|
"#fdb462",
|
||||||
"#b3de69",
|
"#b3de69",
|
||||||
"#fccde5",
|
"#fccde5",
|
||||||
"#d9d9d9",
|
"#d9d9d9",
|
||||||
"#bc80bd",
|
"#bc80bd",
|
||||||
"#ccebc5",
|
"#ccebc5",
|
||||||
"#ffed6f",
|
"#ffed6f",
|
||||||
];
|
];
|
||||||
|
|
||||||
export { COLORS };
|
export { COLORS };
|
||||||
|
|||||||
@@ -1,117 +1,117 @@
|
|||||||
import { COLORS } from "../const";
|
import { COLORS } from "../const";
|
||||||
import { ISOToDatetime } from "../../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
import { ISOToDatetime } from "../../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
||||||
import {
|
import {
|
||||||
DateTime,
|
DateTime,
|
||||||
User,
|
User,
|
||||||
} from "../../../../../../ChillMainBundle/Resources/public/types";
|
} from "../../../../../../ChillMainBundle/Resources/public/types";
|
||||||
import { CalendarLight, CalendarRange, CalendarRemote } from "../../../types";
|
import { CalendarLight, CalendarRange, CalendarRemote } from "../../../types";
|
||||||
import type { EventInputCalendarRange } from "../../../types";
|
import type { EventInputCalendarRange } from "../../../types";
|
||||||
import { EventInput } from "@fullcalendar/core";
|
import { EventInput } from "@fullcalendar/core";
|
||||||
|
|
||||||
export interface UserData {
|
export interface UserData {
|
||||||
user: User;
|
user: User;
|
||||||
calendarRanges: CalendarRange[];
|
calendarRanges: CalendarRange[];
|
||||||
calendarRangesLoaded: {}[];
|
calendarRangesLoaded: {}[];
|
||||||
remotes: CalendarRemote[];
|
remotes: CalendarRemote[];
|
||||||
remotesLoaded: {}[];
|
remotesLoaded: {}[];
|
||||||
locals: CalendarRemote[];
|
locals: CalendarRemote[];
|
||||||
localsLoaded: {}[];
|
localsLoaded: {}[];
|
||||||
mainColor: string;
|
mainColor: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const addIdToValue = (string: string, id: number): string => {
|
export const addIdToValue = (string: string, id: number): string => {
|
||||||
const array = string ? string.split(",") : [];
|
const array = string ? string.split(",") : [];
|
||||||
array.push(id.toString());
|
array.push(id.toString());
|
||||||
const str = array.join();
|
const str = array.join();
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const removeIdFromValue = (string: string, id: number) => {
|
export const removeIdFromValue = (string: string, id: number) => {
|
||||||
let array = string.split(",");
|
let array = string.split(",");
|
||||||
array = array.filter((el) => el !== id.toString());
|
array = array.filter((el) => el !== id.toString());
|
||||||
const str = array.join();
|
const str = array.join();
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Assign missing keys for the ConcernedGroups component
|
* Assign missing keys for the ConcernedGroups component
|
||||||
*/
|
*/
|
||||||
export const mapEntity = (entity: EventInput): EventInput => {
|
export const mapEntity = (entity: EventInput): EventInput => {
|
||||||
const calendar = { ...entity };
|
const calendar = { ...entity };
|
||||||
Object.assign(calendar, { thirdParties: entity.professionals });
|
Object.assign(calendar, { thirdParties: entity.professionals });
|
||||||
|
|
||||||
if (entity.startDate !== null) {
|
if (entity.startDate !== null) {
|
||||||
calendar.startDate = ISOToDatetime(entity.startDate.datetime);
|
calendar.startDate = ISOToDatetime(entity.startDate.datetime);
|
||||||
}
|
}
|
||||||
if (entity.endDate !== null) {
|
if (entity.endDate !== null) {
|
||||||
calendar.endDate = ISOToDatetime(entity.endDate.datetime);
|
calendar.endDate = ISOToDatetime(entity.endDate.datetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity.calendarRange !== null) {
|
if (entity.calendarRange !== null) {
|
||||||
calendar.calendarRange.calendarRangeId = entity.calendarRange.id;
|
calendar.calendarRange.calendarRangeId = entity.calendarRange.id;
|
||||||
calendar.calendarRange.id = `range_${entity.calendarRange.id}`;
|
calendar.calendarRange.id = `range_${entity.calendarRange.id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return calendar;
|
return calendar;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createUserData = (user: User, colorIndex: number): UserData => {
|
export const createUserData = (user: User, colorIndex: number): UserData => {
|
||||||
const colorId = colorIndex % COLORS.length;
|
const colorId = colorIndex % COLORS.length;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user: user,
|
user: user,
|
||||||
calendarRanges: [],
|
calendarRanges: [],
|
||||||
calendarRangesLoaded: [],
|
calendarRangesLoaded: [],
|
||||||
remotes: [],
|
remotes: [],
|
||||||
remotesLoaded: [],
|
remotesLoaded: [],
|
||||||
locals: [],
|
locals: [],
|
||||||
localsLoaded: [],
|
localsLoaded: [],
|
||||||
mainColor: COLORS[colorId],
|
mainColor: COLORS[colorId],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO move this function to a more global namespace, as it is also in use in MyCalendarRange app
|
// TODO move this function to a more global namespace, as it is also in use in MyCalendarRange app
|
||||||
export const calendarRangeToFullCalendarEvent = (
|
export const calendarRangeToFullCalendarEvent = (
|
||||||
entity: CalendarRange,
|
entity: CalendarRange,
|
||||||
): EventInputCalendarRange => {
|
): EventInputCalendarRange => {
|
||||||
return {
|
return {
|
||||||
id: `range_${entity.id}`,
|
id: `range_${entity.id}`,
|
||||||
title: "(" + entity.user.text + ")",
|
title: "(" + entity.user.text + ")",
|
||||||
start: entity.startDate.datetime8601,
|
start: entity.startDate.datetime8601,
|
||||||
end: entity.endDate.datetime8601,
|
end: entity.endDate.datetime8601,
|
||||||
allDay: false,
|
allDay: false,
|
||||||
userId: entity.user.id,
|
userId: entity.user.id,
|
||||||
userLabel: entity.user.label,
|
userLabel: entity.user.label,
|
||||||
calendarRangeId: entity.id,
|
calendarRangeId: entity.id,
|
||||||
locationId: entity.location.id,
|
locationId: entity.location.id,
|
||||||
locationName: entity.location.name,
|
locationName: entity.location.name,
|
||||||
is: "range",
|
is: "range",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const remoteToFullCalendarEvent = (
|
export const remoteToFullCalendarEvent = (
|
||||||
entity: CalendarRemote,
|
entity: CalendarRemote,
|
||||||
): EventInput & { id: string } => {
|
): EventInput & { id: string } => {
|
||||||
return {
|
return {
|
||||||
id: `range_${entity.id}`,
|
id: `range_${entity.id}`,
|
||||||
title: entity.title,
|
title: entity.title,
|
||||||
start: entity.startDate.datetime8601,
|
start: entity.startDate.datetime8601,
|
||||||
end: entity.endDate.datetime8601,
|
end: entity.endDate.datetime8601,
|
||||||
allDay: entity.isAllDay,
|
allDay: entity.isAllDay,
|
||||||
is: "remote",
|
is: "remote",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const localsToFullCalendarEvent = (
|
export const localsToFullCalendarEvent = (
|
||||||
entity: CalendarLight,
|
entity: CalendarLight,
|
||||||
): EventInput & { id: string; originId: number } => {
|
): EventInput & { id: string; originId: number } => {
|
||||||
return {
|
return {
|
||||||
id: `local_${entity.id}`,
|
id: `local_${entity.id}`,
|
||||||
title: entity.persons.map((p) => p.text).join(", "),
|
title: entity.persons.map((p) => p.text).join(", "),
|
||||||
originId: entity.id,
|
originId: entity.id,
|
||||||
start: entity.startDate.datetime8601,
|
start: entity.startDate.datetime8601,
|
||||||
end: entity.endDate.datetime8601,
|
end: entity.endDate.datetime8601,
|
||||||
allDay: false,
|
allDay: false,
|
||||||
is: "local",
|
is: "local",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,50 +1,58 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
<button
|
<button
|
||||||
id="btnGroupDrop1"
|
id="btnGroupDrop1"
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-misc dropdown-toggle"
|
class="btn btn-misc dropdown-toggle"
|
||||||
data-bs-toggle="dropdown"
|
data-bs-toggle="dropdown"
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
>
|
|
||||||
<template v-if="status === Statuses.PENDING">
|
|
||||||
<span class="fa fa-hourglass"></span> {{ $t("Give_an_answer") }}
|
|
||||||
</template>
|
|
||||||
<template v-else-if="status === Statuses.ACCEPTED">
|
|
||||||
<span class="fa fa-check"></span> {{ $t("Accepted") }}
|
|
||||||
</template>
|
|
||||||
<template v-else-if="status === Statuses.DECLINED">
|
|
||||||
<span class="fa fa-times"></span> {{ $t("Declined") }}
|
|
||||||
</template>
|
|
||||||
<template v-else-if="status === Statuses.TENTATIVELY_ACCEPTED">
|
|
||||||
<span class="fa fa-question"></span> {{ $t("Tentative") }}
|
|
||||||
</template>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
|
|
||||||
<li v-if="status !== Statuses.ACCEPTED">
|
|
||||||
<a class="dropdown-item" @click="changeStatus(Statuses.ACCEPTED)"
|
|
||||||
><i class="fa fa-check" aria-hidden="true"></i> {{ $t("Accept") }}</a
|
|
||||||
>
|
>
|
||||||
</li>
|
<template v-if="status === Statuses.PENDING">
|
||||||
<li v-if="status !== Statuses.DECLINED">
|
<span class="fa fa-hourglass"></span> {{ $t("Give_an_answer") }}
|
||||||
<a class="dropdown-item" @click="changeStatus(Statuses.DECLINED)"
|
</template>
|
||||||
><i class="fa fa-times" aria-hidden="true"></i> {{ $t("Decline") }}</a
|
<template v-else-if="status === Statuses.ACCEPTED">
|
||||||
>
|
<span class="fa fa-check"></span> {{ $t("Accepted") }}
|
||||||
</li>
|
</template>
|
||||||
<li v-if="status !== Statuses.TENTATIVELY_ACCEPTED">
|
<template v-else-if="status === Statuses.DECLINED">
|
||||||
<a
|
<span class="fa fa-times"></span> {{ $t("Declined") }}
|
||||||
class="dropdown-item"
|
</template>
|
||||||
@click="changeStatus(Statuses.TENTATIVELY_ACCEPTED)"
|
<template v-else-if="status === Statuses.TENTATIVELY_ACCEPTED">
|
||||||
><i class="fa fa-question"></i> {{ $t("Tentatively_accept") }}</a
|
<span class="fa fa-question"></span> {{ $t("Tentative") }}
|
||||||
>
|
</template>
|
||||||
</li>
|
</button>
|
||||||
<li v-if="status !== Statuses.PENDING">
|
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
|
||||||
<a class="dropdown-item" @click="changeStatus(Statuses.PENDING)"
|
<li v-if="status !== Statuses.ACCEPTED">
|
||||||
><i class="fa fa-hourglass-o"></i> {{ $t("Set_pending") }}</a
|
<a
|
||||||
>
|
class="dropdown-item"
|
||||||
</li>
|
@click="changeStatus(Statuses.ACCEPTED)"
|
||||||
</ul>
|
><i class="fa fa-check" aria-hidden="true"></i>
|
||||||
</div>
|
{{ $t("Accept") }}</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li v-if="status !== Statuses.DECLINED">
|
||||||
|
<a
|
||||||
|
class="dropdown-item"
|
||||||
|
@click="changeStatus(Statuses.DECLINED)"
|
||||||
|
><i class="fa fa-times" aria-hidden="true"></i>
|
||||||
|
{{ $t("Decline") }}</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li v-if="status !== Statuses.TENTATIVELY_ACCEPTED">
|
||||||
|
<a
|
||||||
|
class="dropdown-item"
|
||||||
|
@click="changeStatus(Statuses.TENTATIVELY_ACCEPTED)"
|
||||||
|
><i class="fa fa-question"></i>
|
||||||
|
{{ $t("Tentatively_accept") }}</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li v-if="status !== Statuses.PENDING">
|
||||||
|
<a class="dropdown-item" @click="changeStatus(Statuses.PENDING)"
|
||||||
|
><i class="fa fa-hourglass-o"></i>
|
||||||
|
{{ $t("Set_pending") }}</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -56,67 +64,69 @@ const PENDING = "pending";
|
|||||||
const TENTATIVELY_ACCEPTED = "tentative";
|
const TENTATIVELY_ACCEPTED = "tentative";
|
||||||
|
|
||||||
const i18n = {
|
const i18n = {
|
||||||
messages: {
|
messages: {
|
||||||
fr: {
|
fr: {
|
||||||
Give_an_answer: "Répondre",
|
Give_an_answer: "Répondre",
|
||||||
Accepted: "Accepté",
|
Accepted: "Accepté",
|
||||||
Declined: "Refusé",
|
Declined: "Refusé",
|
||||||
Tentative: "Accepté provisoirement",
|
Tentative: "Accepté provisoirement",
|
||||||
Accept: "Accepter",
|
Accept: "Accepter",
|
||||||
Decline: "Refuser",
|
Decline: "Refuser",
|
||||||
Tentatively_accept: "Accepter provisoirement",
|
Tentatively_accept: "Accepter provisoirement",
|
||||||
Set_pending: "Ne pas répondre",
|
Set_pending: "Ne pas répondre",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "Answer",
|
name: "Answer",
|
||||||
i18n,
|
i18n,
|
||||||
props: {
|
props: {
|
||||||
calendarId: { type: Number, required: true },
|
calendarId: { type: Number, required: true },
|
||||||
status: {
|
status: {
|
||||||
type: String as PropType<
|
type: String as PropType<
|
||||||
"accepted" | "declined" | "pending" | "tentative"
|
"accepted" | "declined" | "pending" | "tentative"
|
||||||
>,
|
>,
|
||||||
required: true,
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
emits: {
|
||||||
emits: {
|
statusChanged(
|
||||||
statusChanged(payload: "accepted" | "declined" | "pending" | "tentative") {
|
payload: "accepted" | "declined" | "pending" | "tentative",
|
||||||
return true;
|
) {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
data() {
|
||||||
data() {
|
return {
|
||||||
return {
|
Statuses: {
|
||||||
Statuses: {
|
ACCEPTED,
|
||||||
ACCEPTED,
|
DECLINED,
|
||||||
DECLINED,
|
PENDING,
|
||||||
PENDING,
|
TENTATIVELY_ACCEPTED,
|
||||||
TENTATIVELY_ACCEPTED,
|
},
|
||||||
},
|
};
|
||||||
};
|
},
|
||||||
},
|
methods: {
|
||||||
methods: {
|
changeStatus: function (
|
||||||
changeStatus: function (
|
newStatus: "accepted" | "declined" | "pending" | "tentative",
|
||||||
newStatus: "accepted" | "declined" | "pending" | "tentative",
|
) {
|
||||||
) {
|
console.log("changeStatus", newStatus);
|
||||||
console.log("changeStatus", newStatus);
|
const url = `/api/1.0/calendar/calendar/${this.$props.calendarId}/answer/${newStatus}.json`;
|
||||||
const url = `/api/1.0/calendar/calendar/${this.$props.calendarId}/answer/${newStatus}.json`;
|
window
|
||||||
window
|
.fetch(url, {
|
||||||
.fetch(url, {
|
method: "POST",
|
||||||
method: "POST",
|
})
|
||||||
})
|
.then((r: Response) => {
|
||||||
.then((r: Response) => {
|
if (!r.ok) {
|
||||||
if (!r.ok) {
|
console.error("could not confirm answer", newStatus);
|
||||||
console.error("could not confirm answer", newStatus);
|
return;
|
||||||
return;
|
}
|
||||||
}
|
console.log("answer sent", newStatus);
|
||||||
console.log("answer sent", newStatus);
|
this.$emit("statusChanged", newStatus);
|
||||||
this.$emit("statusChanged", newStatus);
|
});
|
||||||
});
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,185 +1,231 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm">
|
<div class="col-sm">
|
||||||
<label class="form-label">{{ $t("created_availabilities") }}</label>
|
<label class="form-label">{{ $t("created_availabilities") }}</label>
|
||||||
<vue-multiselect
|
<vue-multiselect
|
||||||
v-model="pickedLocation"
|
v-model="pickedLocation"
|
||||||
:options="locations"
|
:options="locations"
|
||||||
:label="'name'"
|
:label="'name'"
|
||||||
:track-by="'id'"
|
:track-by="'id'"
|
||||||
:selectLabel="'Presser \'Entrée\' pour choisir'"
|
:selectLabel="'Presser \'Entrée\' pour choisir'"
|
||||||
:selectedLabel="'Choisir'"
|
:selectedLabel="'Choisir'"
|
||||||
:deselectLabel="'Presser \'Entrée\' pour enlever'"
|
:deselectLabel="'Presser \'Entrée\' pour enlever'"
|
||||||
:placeholder="'Choisir'"
|
:placeholder="'Choisir'"
|
||||||
></vue-multiselect>
|
></vue-multiselect>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="display-options row justify-content-between"
|
|
||||||
style="margin-top: 1rem"
|
|
||||||
>
|
|
||||||
<div class="col-sm-9 col-xs-12">
|
|
||||||
<div class="input-group mb-3">
|
|
||||||
<label class="input-group-text" for="slotDuration"
|
|
||||||
>Durée des créneaux</label
|
|
||||||
>
|
|
||||||
<select v-model="slotDuration" id="slotDuration" class="form-select">
|
|
||||||
<option value="00:05:00">5 minutes</option>
|
|
||||||
<option value="00:10:00">10 minutes</option>
|
|
||||||
<option value="00:15:00">15 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>
|
|
||||||
<label class="input-group-text" for="slotMinTime">De</label>
|
|
||||||
<select v-model="slotMinTime" id="slotMinTime" class="form-select">
|
|
||||||
<option value="00:00:00">0h</option>
|
|
||||||
<option value="01:00:00">1h</option>
|
|
||||||
<option value="02:00:00">2h</option>
|
|
||||||
<option value="03:00:00">3h</option>
|
|
||||||
<option value="04:00:00">4h</option>
|
|
||||||
<option value="05:00:00">5h</option>
|
|
||||||
<option value="06:00:00">6h</option>
|
|
||||||
<option value="07:00:00">7h</option>
|
|
||||||
<option value="08:00:00">8h</option>
|
|
||||||
<option value="09:00:00">9h</option>
|
|
||||||
<option value="10:00:00">10h</option>
|
|
||||||
<option value="11:00:00">11h</option>
|
|
||||||
<option value="12:00:00">12h</option>
|
|
||||||
</select>
|
|
||||||
<label class="input-group-text" for="slotMaxTime">À</label>
|
|
||||||
<select v-model="slotMaxTime" id="slotMaxTime" class="form-select">
|
|
||||||
<option value="12:00:00">12h</option>
|
|
||||||
<option value="13:00:00">13h</option>
|
|
||||||
<option value="14:00:00">14h</option>
|
|
||||||
<option value="15:00:00">15h</option>
|
|
||||||
<option value="16:00:00">16h</option>
|
|
||||||
<option value="17:00:00">17h</option>
|
|
||||||
<option value="18:00:00">18h</option>
|
|
||||||
<option value="19:00:00">19h</option>
|
|
||||||
<option value="20:00:00">20h</option>
|
|
||||||
<option value="21:00:00">21h</option>
|
|
||||||
<option value="22:00:00">22h</option>
|
|
||||||
<option value="23:00:00">23h</option>
|
|
||||||
<option value="23:59:59">24h</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-12 col-sm-3">
|
|
||||||
<div class="float-end">
|
|
||||||
<div class="form-check input-group">
|
|
||||||
<span class="input-group-text">
|
|
||||||
<input
|
|
||||||
id="showHideWE"
|
|
||||||
class="mt-0"
|
|
||||||
type="checkbox"
|
|
||||||
v-model="showWeekends"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<label for="showHideWE" class="form-check-label input-group-text"
|
|
||||||
>Week-ends</label
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div
|
||||||
<FullCalendar :options="calendarOptions" ref="calendarRef">
|
class="display-options row justify-content-between"
|
||||||
<template v-slot:eventContent="{ event }: { event: EventApi }">
|
style="margin-top: 1rem"
|
||||||
<span :class="eventClasses">
|
>
|
||||||
<b v-if="event.extendedProps.is === 'remote'">{{ event.title }}</b>
|
<div class="col-sm-9 col-xs-12">
|
||||||
<b v-else-if="event.extendedProps.is === 'range'"
|
<div class="input-group mb-3">
|
||||||
>{{ formatDate(event.startStr, "time") }} -
|
<label class="input-group-text" for="slotDuration"
|
||||||
{{ formatDate(event.endStr, "time") }}:
|
>Durée des créneaux</label
|
||||||
{{ event.extendedProps.locationName }}</b
|
>
|
||||||
>
|
<select
|
||||||
<a
|
v-model="slotDuration"
|
||||||
:href="calendarLink(event.id)"
|
id="slotDuration"
|
||||||
v-else-if="event.extendedProps.is === 'local'"
|
class="form-select"
|
||||||
>
|
>
|
||||||
<b>{{ event.title }}</b>
|
<option value="00:05:00">5 minutes</option>
|
||||||
</a>
|
<option value="00:10:00">10 minutes</option>
|
||||||
<b v-else>no 'is'</b>
|
<option value="00:15:00">15 minutes</option>
|
||||||
<a
|
<option value="00:30:00">30 minutes</option>
|
||||||
v-if="event.extendedProps.is === 'range'"
|
<option value="00:45:00">45 minutes</option>
|
||||||
class="fa fa-fw fa-times delete"
|
<option value="00:60:00">60 minutes</option>
|
||||||
@click.prevent="onClickDelete(event)"
|
</select>
|
||||||
>
|
<label class="input-group-text" for="slotMinTime">De</label>
|
||||||
</a>
|
<select
|
||||||
</span>
|
v-model="slotMinTime"
|
||||||
</template>
|
id="slotMinTime"
|
||||||
</FullCalendar>
|
class="form-select"
|
||||||
|
>
|
||||||
<div id="copy-widget">
|
<option value="00:00:00">0h</option>
|
||||||
<div class="container mt-2 mb-2">
|
<option value="01:00:00">1h</option>
|
||||||
<div class="row justify-content-between align-items-center mb-4">
|
<option value="02:00:00">2h</option>
|
||||||
<div class="col-xs-12 col-sm-3 col-md-2">
|
<option value="03:00:00">3h</option>
|
||||||
<h6 class="chill-red">{{ $t("copy_range_from_to") }}</h6>
|
<option value="04:00:00">4h</option>
|
||||||
|
<option value="05:00:00">5h</option>
|
||||||
|
<option value="06:00:00">6h</option>
|
||||||
|
<option value="07:00:00">7h</option>
|
||||||
|
<option value="08:00:00">8h</option>
|
||||||
|
<option value="09:00:00">9h</option>
|
||||||
|
<option value="10:00:00">10h</option>
|
||||||
|
<option value="11:00:00">11h</option>
|
||||||
|
<option value="12:00:00">12h</option>
|
||||||
|
</select>
|
||||||
|
<label class="input-group-text" for="slotMaxTime">À</label>
|
||||||
|
<select
|
||||||
|
v-model="slotMaxTime"
|
||||||
|
id="slotMaxTime"
|
||||||
|
class="form-select"
|
||||||
|
>
|
||||||
|
<option value="12:00:00">12h</option>
|
||||||
|
<option value="13:00:00">13h</option>
|
||||||
|
<option value="14:00:00">14h</option>
|
||||||
|
<option value="15:00:00">15h</option>
|
||||||
|
<option value="16:00:00">16h</option>
|
||||||
|
<option value="17:00:00">17h</option>
|
||||||
|
<option value="18:00:00">18h</option>
|
||||||
|
<option value="19:00:00">19h</option>
|
||||||
|
<option value="20:00:00">20h</option>
|
||||||
|
<option value="21:00:00">21h</option>
|
||||||
|
<option value="22:00:00">22h</option>
|
||||||
|
<option value="23:00:00">23h</option>
|
||||||
|
<option value="23:59:59">24h</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-sm-9 col-md-2">
|
<div class="col-xs-12 col-sm-3">
|
||||||
<select v-model="dayOrWeek" id="dayOrWeek" class="form-select">
|
<div class="float-end">
|
||||||
<option value="day">{{ $t("from_day_to_day") }}</option>
|
<div class="form-check input-group">
|
||||||
<option value="week">
|
<span class="input-group-text">
|
||||||
{{ $t("from_week_to_week") }}
|
<input
|
||||||
</option>
|
id="showHideWE"
|
||||||
</select>
|
class="mt-0"
|
||||||
|
type="checkbox"
|
||||||
|
v-model="showWeekends"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<label
|
||||||
|
for="showHideWE"
|
||||||
|
class="form-check-label input-group-text"
|
||||||
|
>Week-ends</label
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="dayOrWeek === 'day'">
|
</div>
|
||||||
<div class="col-xs-12 col-sm-3 col-md-3">
|
<FullCalendar :options="calendarOptions" ref="calendarRef">
|
||||||
<input class="form-control" type="date" v-model="copyFrom" />
|
<template v-slot:eventContent="{ event }: { event: EventApi }">
|
||||||
</div>
|
<span :class="eventClasses">
|
||||||
<div class="col-xs-12 col-sm-1 col-md-1 copy-chevron">
|
<b v-if="event.extendedProps.is === 'remote'">{{
|
||||||
<i class="fa fa-angle-double-right"></i>
|
event.title
|
||||||
</div>
|
}}</b>
|
||||||
<div class="col-xs-12 col-sm-3 col-md-3">
|
<b v-else-if="event.extendedProps.is === 'range'"
|
||||||
<input class="form-control" type="date" v-model="copyTo" />
|
>{{ formatDate(event.startStr, "time") }} -
|
||||||
</div>
|
{{ formatDate(event.endStr, "time") }}:
|
||||||
<div class="col-xs-12 col-sm-5 col-md-1">
|
{{ event.extendedProps.locationName }}</b
|
||||||
<button class="btn btn-action float-end" @click="copyDay">
|
>
|
||||||
{{ $t("copy_range") }}
|
<a
|
||||||
</button>
|
:href="calendarLink(event.id)"
|
||||||
</div>
|
v-else-if="event.extendedProps.is === 'local'"
|
||||||
|
>
|
||||||
|
<b>{{ event.title }}</b>
|
||||||
|
</a>
|
||||||
|
<b v-else>no 'is'</b>
|
||||||
|
<a
|
||||||
|
v-if="event.extendedProps.is === 'range'"
|
||||||
|
class="fa fa-fw fa-times delete"
|
||||||
|
@click.prevent="onClickDelete(event)"
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
</FullCalendar>
|
||||||
<div class="col-xs-12 col-sm-3 col-md-3">
|
|
||||||
<select
|
|
||||||
v-model="copyFromWeek"
|
|
||||||
id="copyFromWeek"
|
|
||||||
class="form-select"
|
|
||||||
>
|
|
||||||
<option v-for="w in lastWeeks" :value="w.value" :key="w.value">
|
|
||||||
{{ w.text }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-12 col-sm-1 col-md-1 copy-chevron">
|
|
||||||
<i class="fa fa-angle-double-right"></i>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-12 col-sm-3 col-md-3">
|
|
||||||
<select v-model="copyToWeek" id="copyToWeek" class="form-select">
|
|
||||||
<option v-for="w in nextWeeks" :value="w.value" :key="w.value">
|
|
||||||
{{ w.text }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-12 col-sm-5 col-md-1">
|
|
||||||
<button class="btn btn-action float-end" @click="copyWeek">
|
|
||||||
{{ $t("copy_range") }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- not directly seen, but include in a modal -->
|
<div id="copy-widget">
|
||||||
<edit-location ref="editLocation"></edit-location>
|
<div class="container mt-2 mb-2">
|
||||||
|
<div class="row justify-content-between align-items-center mb-4">
|
||||||
|
<div class="col-xs-12 col-sm-3 col-md-2">
|
||||||
|
<h6 class="chill-red">{{ $t("copy_range_from_to") }}</h6>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-sm-9 col-md-2">
|
||||||
|
<select
|
||||||
|
v-model="dayOrWeek"
|
||||||
|
id="dayOrWeek"
|
||||||
|
class="form-select"
|
||||||
|
>
|
||||||
|
<option value="day">{{ $t("from_day_to_day") }}</option>
|
||||||
|
<option value="week">
|
||||||
|
{{ $t("from_week_to_week") }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<template v-if="dayOrWeek === 'day'">
|
||||||
|
<div class="col-xs-12 col-sm-3 col-md-3">
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
type="date"
|
||||||
|
v-model="copyFrom"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-sm-1 col-md-1 copy-chevron">
|
||||||
|
<i class="fa fa-angle-double-right"></i>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-sm-3 col-md-3">
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
type="date"
|
||||||
|
v-model="copyTo"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-sm-5 col-md-1">
|
||||||
|
<button
|
||||||
|
class="btn btn-action float-end"
|
||||||
|
@click="copyDay"
|
||||||
|
>
|
||||||
|
{{ $t("copy_range") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="col-xs-12 col-sm-3 col-md-3">
|
||||||
|
<select
|
||||||
|
v-model="copyFromWeek"
|
||||||
|
id="copyFromWeek"
|
||||||
|
class="form-select"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="w in lastWeeks"
|
||||||
|
:value="w.value"
|
||||||
|
:key="w.value"
|
||||||
|
>
|
||||||
|
{{ w.text }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-sm-1 col-md-1 copy-chevron">
|
||||||
|
<i class="fa fa-angle-double-right"></i>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-sm-3 col-md-3">
|
||||||
|
<select
|
||||||
|
v-model="copyToWeek"
|
||||||
|
id="copyToWeek"
|
||||||
|
class="form-select"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="w in nextWeeks"
|
||||||
|
:value="w.value"
|
||||||
|
:key="w.value"
|
||||||
|
>
|
||||||
|
{{ w.text }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-sm-5 col-md-1">
|
||||||
|
<button
|
||||||
|
class="btn btn-action float-end"
|
||||||
|
@click="copyWeek"
|
||||||
|
>
|
||||||
|
{{ $t("copy_range") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- not directly seen, but include in a modal -->
|
||||||
|
<edit-location ref="editLocation"></edit-location>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type {
|
import type {
|
||||||
CalendarOptions,
|
CalendarOptions,
|
||||||
DatesSetArg,
|
DatesSetArg,
|
||||||
EventInput,
|
EventInput,
|
||||||
} from "@fullcalendar/core";
|
} from "@fullcalendar/core";
|
||||||
import { computed, ref, onMounted } from "vue";
|
import { computed, ref, onMounted } from "vue";
|
||||||
import { useStore } from "vuex";
|
import { useStore } from "vuex";
|
||||||
@@ -187,14 +233,14 @@ import { key } from "./store";
|
|||||||
import FullCalendar from "@fullcalendar/vue3";
|
import FullCalendar from "@fullcalendar/vue3";
|
||||||
import frLocale from "@fullcalendar/core/locales/fr";
|
import frLocale from "@fullcalendar/core/locales/fr";
|
||||||
import interactionPlugin, {
|
import interactionPlugin, {
|
||||||
EventResizeDoneArg,
|
EventResizeDoneArg,
|
||||||
} from "@fullcalendar/interaction";
|
} from "@fullcalendar/interaction";
|
||||||
import timeGridPlugin from "@fullcalendar/timegrid";
|
import timeGridPlugin from "@fullcalendar/timegrid";
|
||||||
import {
|
import {
|
||||||
EventApi,
|
EventApi,
|
||||||
DateSelectArg,
|
DateSelectArg,
|
||||||
EventDropArg,
|
EventDropArg,
|
||||||
EventClickArg,
|
EventClickArg,
|
||||||
} from "@fullcalendar/core";
|
} from "@fullcalendar/core";
|
||||||
import { dateToISO, ISOToDate } from "ChillMainAssets/chill/js/date";
|
import { dateToISO, ISOToDate } from "ChillMainAssets/chill/js/date";
|
||||||
import VueMultiselect from "vue-multiselect";
|
import VueMultiselect from "vue-multiselect";
|
||||||
@@ -215,113 +261,113 @@ const copyFromWeek = ref<string | null>(null);
|
|||||||
const copyToWeek = ref<string | null>(null);
|
const copyToWeek = ref<string | null>(null);
|
||||||
|
|
||||||
interface Weeks {
|
interface Weeks {
|
||||||
value: string | null;
|
value: string | null;
|
||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getMonday = (week: number): Date => {
|
const getMonday = (week: number): Date => {
|
||||||
const lastMonday = new Date();
|
const lastMonday = new Date();
|
||||||
lastMonday.setDate(
|
lastMonday.setDate(
|
||||||
lastMonday.getDate() - ((lastMonday.getDay() + 6) % 7) + week * 7,
|
lastMonday.getDate() - ((lastMonday.getDay() + 6) % 7) + week * 7,
|
||||||
);
|
);
|
||||||
return lastMonday;
|
return lastMonday;
|
||||||
};
|
};
|
||||||
|
|
||||||
const dateOptions: Intl.DateTimeFormatOptions = {
|
const dateOptions: Intl.DateTimeFormatOptions = {
|
||||||
weekday: "long",
|
weekday: "long",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
month: "long",
|
month: "long",
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
};
|
};
|
||||||
|
|
||||||
const lastWeeks = computed((): Weeks[] =>
|
const lastWeeks = computed((): Weeks[] =>
|
||||||
Array.from(Array(30).keys()).map((w) => {
|
Array.from(Array(30).keys()).map((w) => {
|
||||||
const lastMonday = getMonday(15 - w);
|
const lastMonday = getMonday(15 - w);
|
||||||
return {
|
return {
|
||||||
value: dateToISO(lastMonday),
|
value: dateToISO(lastMonday),
|
||||||
text: `Semaine du ${lastMonday.toLocaleDateString("fr-FR", dateOptions)}`,
|
text: `Semaine du ${lastMonday.toLocaleDateString("fr-FR", dateOptions)}`,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const nextWeeks = computed((): Weeks[] =>
|
const nextWeeks = computed((): Weeks[] =>
|
||||||
Array.from(Array(52).keys()).map((w) => {
|
Array.from(Array(52).keys()).map((w) => {
|
||||||
const nextMonday = getMonday(w + 1);
|
const nextMonday = getMonday(w + 1);
|
||||||
return {
|
return {
|
||||||
value: dateToISO(nextMonday),
|
value: dateToISO(nextMonday),
|
||||||
text: `Semaine du ${nextMonday.toLocaleDateString("fr-FR", dateOptions)}`,
|
text: `Semaine du ${nextMonday.toLocaleDateString("fr-FR", dateOptions)}`,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const formatDate = (datetime: string, format: null | "time" = null) => {
|
const formatDate = (datetime: string, format: null | "time" = null) => {
|
||||||
const date = ISOToDate(datetime);
|
const date = ISOToDate(datetime);
|
||||||
if (!date) return "";
|
if (!date) return "";
|
||||||
|
|
||||||
if (format === "time") {
|
if (format === "time") {
|
||||||
return date.toLocaleTimeString("fr-FR", {
|
return date.toLocaleTimeString("fr-FR", {
|
||||||
hour: "2-digit",
|
hour: "2-digit",
|
||||||
minute: "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",
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// 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>({
|
||||||
locale: frLocale,
|
locale: frLocale,
|
||||||
plugins: [interactionPlugin, timeGridPlugin],
|
plugins: [interactionPlugin, timeGridPlugin],
|
||||||
initialView: "timeGridWeek",
|
initialView: "timeGridWeek",
|
||||||
initialDate: new Date(),
|
initialDate: new Date(),
|
||||||
scrollTimeReset: false,
|
scrollTimeReset: false,
|
||||||
selectable: true,
|
selectable: true,
|
||||||
// when the dates are changes in the fullcalendar view OR when new events are added
|
// when the dates are changes in the fullcalendar view OR when new events are added
|
||||||
datesSet: onDatesSet,
|
datesSet: onDatesSet,
|
||||||
// when a date is selected
|
// when a date is selected
|
||||||
select: onDateSelect,
|
select: onDateSelect,
|
||||||
// when a event is resized
|
// when a event is resized
|
||||||
eventResize: onEventDropOrResize,
|
eventResize: onEventDropOrResize,
|
||||||
// when an event is moved
|
// when an event is moved
|
||||||
eventDrop: onEventDropOrResize,
|
eventDrop: onEventDropOrResize,
|
||||||
// when an event si clicked
|
// when an event si clicked
|
||||||
eventClick: onEventClick,
|
eventClick: onEventClick,
|
||||||
selectMirror: false,
|
selectMirror: false,
|
||||||
editable: true,
|
editable: true,
|
||||||
headerToolbar: {
|
headerToolbar: {
|
||||||
left: "prev,next today",
|
left: "prev,next today",
|
||||||
center: "title",
|
center: "title",
|
||||||
right: "timeGridWeek,timeGridDay",
|
right: "timeGridWeek,timeGridDay",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const ranges = computed<EventInput[]>(() => {
|
const ranges = computed<EventInput[]>(() => {
|
||||||
return store.state.calendarRanges.ranges;
|
return store.state.calendarRanges.ranges;
|
||||||
});
|
});
|
||||||
|
|
||||||
const locations = computed<Location[]>(() => {
|
const locations = computed<Location[]>(() => {
|
||||||
return store.state.locations.locations;
|
return store.state.locations.locations;
|
||||||
});
|
});
|
||||||
|
|
||||||
const pickedLocation = computed<Location | null>({
|
const pickedLocation = computed<Location | null>({
|
||||||
get(): Location | null {
|
get(): Location | null {
|
||||||
return (
|
return (
|
||||||
store.state.locations.locationPicked ||
|
store.state.locations.locationPicked ||
|
||||||
store.state.locations.currentLocation
|
store.state.locations.currentLocation
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
set(newLocation: Location | null): void {
|
set(newLocation: Location | null): void {
|
||||||
store.commit("locations/setLocationPicked", newLocation, {
|
store.commit("locations/setLocationPicked", newLocation, {
|
||||||
root: true,
|
root: true,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -350,122 +396,122 @@ const sources = computed<EventSourceInput[]>(() => {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const calendarOptions = computed((): CalendarOptions => {
|
const calendarOptions = computed((): CalendarOptions => {
|
||||||
return {
|
return {
|
||||||
...baseOptions.value,
|
...baseOptions.value,
|
||||||
weekends: showWeekends.value,
|
weekends: showWeekends.value,
|
||||||
slotDuration: slotDuration.value,
|
slotDuration: slotDuration.value,
|
||||||
events: ranges.value,
|
events: ranges.value,
|
||||||
slotMinTime: slotMinTime.value,
|
slotMinTime: slotMinTime.value,
|
||||||
slotMaxTime: slotMaxTime.value,
|
slotMaxTime: slotMaxTime.value,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* launched when the calendar range date change
|
* launched when the calendar range date change
|
||||||
*/
|
*/
|
||||||
function onDatesSet(event: DatesSetArg): void {
|
function onDatesSet(event: DatesSetArg): void {
|
||||||
store.dispatch("fullCalendar/setCurrentDatesView", {
|
store.dispatch("fullCalendar/setCurrentDatesView", {
|
||||||
start: event.start,
|
start: event.start,
|
||||||
end: event.end,
|
end: event.end,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDateSelect(event: DateSelectArg): void {
|
function onDateSelect(event: DateSelectArg): void {
|
||||||
if (null === pickedLocation.value) {
|
if (null === pickedLocation.value) {
|
||||||
window.alert(
|
window.alert(
|
||||||
"Indiquez une localisation avant de créer une période de disponibilité.",
|
"Indiquez une localisation avant de créer une période de disponibilité.",
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
store.dispatch("calendarRanges/createRange", {
|
store.dispatch("calendarRanges/createRange", {
|
||||||
start: event.start,
|
start: event.start,
|
||||||
end: event.end,
|
end: event.end,
|
||||||
location: pickedLocation.value,
|
location: pickedLocation.value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When a calendar range is deleted
|
* When a calendar range is deleted
|
||||||
*/
|
*/
|
||||||
function onClickDelete(event: EventApi): void {
|
function onClickDelete(event: EventApi): void {
|
||||||
if (event.extendedProps.is !== "range") {
|
if (event.extendedProps.is !== "range") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
"calendarRanges/deleteRange",
|
"calendarRanges/deleteRange",
|
||||||
event.extendedProps.calendarRangeId,
|
event.extendedProps.calendarRangeId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEventDropOrResize(payload: EventDropArg | EventResizeDoneArg) {
|
function onEventDropOrResize(payload: EventDropArg | EventResizeDoneArg) {
|
||||||
if (payload.event.extendedProps.is !== "range") {
|
if (payload.event.extendedProps.is !== "range") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
store.dispatch("calendarRanges/patchRangeTime", {
|
store.dispatch("calendarRanges/patchRangeTime", {
|
||||||
calendarRangeId: payload.event.extendedProps.calendarRangeId,
|
calendarRangeId: payload.event.extendedProps.calendarRangeId,
|
||||||
start: payload.event.start,
|
start: payload.event.start,
|
||||||
end: payload.event.end,
|
end: payload.event.end,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEventClick(payload: EventClickArg): void {
|
function onEventClick(payload: EventClickArg): void {
|
||||||
// @ts-ignore TS does not recognize the target. But it does exists.
|
// @ts-ignore TS does not recognize the target. But it does exists.
|
||||||
if (payload.jsEvent.target.classList.contains("delete")) {
|
if (payload.jsEvent.target.classList.contains("delete")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (payload.event.extendedProps.is !== "range") {
|
if (payload.event.extendedProps.is !== "range") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
editLocation.value?.startEdit(payload.event);
|
editLocation.value?.startEdit(payload.event);
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyDay() {
|
function copyDay() {
|
||||||
if (null === copyFrom.value || null === copyTo.value) {
|
if (null === copyFrom.value || null === copyTo.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
store.dispatch("calendarRanges/copyFromDayToAnotherDay", {
|
store.dispatch("calendarRanges/copyFromDayToAnotherDay", {
|
||||||
from: ISOToDate(copyFrom.value),
|
from: ISOToDate(copyFrom.value),
|
||||||
to: ISOToDate(copyTo.value),
|
to: ISOToDate(copyTo.value),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyWeek() {
|
function copyWeek() {
|
||||||
if (null === copyFromWeek.value || null === copyToWeek.value) {
|
if (null === copyFromWeek.value || null === copyToWeek.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
store.dispatch("calendarRanges/copyFromWeekToAnotherWeek", {
|
store.dispatch("calendarRanges/copyFromWeekToAnotherWeek", {
|
||||||
fromMonday: ISOToDate(copyFromWeek.value),
|
fromMonday: ISOToDate(copyFromWeek.value),
|
||||||
toMonday: ISOToDate(copyToWeek.value),
|
toMonday: ISOToDate(copyToWeek.value),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const calendarLink = (calendarId: string) => {
|
const calendarLink = (calendarId: string) => {
|
||||||
const idStr = calendarId.match(/_(\d+)$/)?.[1];
|
const idStr = calendarId.match(/_(\d+)$/)?.[1];
|
||||||
|
|
||||||
return `/fr/calendar/calendar/${idStr}/edit`;
|
return `/fr/calendar/calendar/${idStr}/edit`;
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
copyFromWeek.value = dateToISO(getMonday(0));
|
copyFromWeek.value = dateToISO(getMonday(0));
|
||||||
copyToWeek.value = dateToISO(getMonday(1));
|
copyToWeek.value = dateToISO(getMonday(1));
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
#copy-widget {
|
#copy-widget {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
z-index: 9999999999;
|
z-index: 9999999999;
|
||||||
padding: 0.25rem 0 0.25rem;
|
padding: 0.25rem 0 0.25rem;
|
||||||
}
|
}
|
||||||
div.copy-chevron {
|
div.copy-chevron {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: x-large;
|
font-size: x-large;
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="Teleport" to="body">
|
<component :is="Teleport" to="body">
|
||||||
<modal v-if="showModal" @close="closeModal">
|
<modal v-if="showModal" @close="closeModal">
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
<h3>{{ "Modifier le lieu" }}</h3>
|
<h3>{{ "Modifier le lieu" }}</h3>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:body>
|
<template v-slot:body>
|
||||||
<div></div>
|
<div></div>
|
||||||
<label>Localisation</label>
|
<label>Localisation</label>
|
||||||
<vue-multiselect
|
<vue-multiselect
|
||||||
v-model="location"
|
v-model="location"
|
||||||
:options="locations"
|
:options="locations"
|
||||||
:label="'name'"
|
:label="'name'"
|
||||||
:track-by="'id'"
|
:track-by="'id'"
|
||||||
></vue-multiselect>
|
></vue-multiselect>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:footer>
|
<template v-slot:footer>
|
||||||
<button class="btn btn-save" @click="saveAndClose">
|
<button class="btn btn-save" @click="saveAndClose">
|
||||||
{{ "Enregistrer" }}
|
{{ "Enregistrer" }}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
</modal>
|
</modal>
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -39,7 +39,7 @@ import VueMultiselect from "vue-multiselect";
|
|||||||
import { Teleport as teleport_, TeleportProps, VNodeProps } from "vue";
|
import { Teleport as teleport_, TeleportProps, VNodeProps } from "vue";
|
||||||
|
|
||||||
const Teleport = teleport_ as new () => {
|
const Teleport = teleport_ as new () => {
|
||||||
$props: VNodeProps & TeleportProps;
|
$props: VNodeProps & TeleportProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
const store = useStore(key);
|
const store = useStore(key);
|
||||||
@@ -50,37 +50,37 @@ const showModal = ref(false);
|
|||||||
//const tele = ref<InstanceType<typeof Teleport> | null>(null);
|
//const tele = ref<InstanceType<typeof Teleport> | null>(null);
|
||||||
|
|
||||||
const locations = computed<Location[]>(() => {
|
const locations = computed<Location[]>(() => {
|
||||||
return store.state.locations.locations;
|
return store.state.locations.locations;
|
||||||
});
|
});
|
||||||
|
|
||||||
const startEdit = function (event: EventApi): void {
|
const startEdit = function (event: EventApi): void {
|
||||||
console.log("startEditing", event);
|
console.log("startEditing", event);
|
||||||
calendarRangeId.value = event.extendedProps.calendarRangeId;
|
calendarRangeId.value = event.extendedProps.calendarRangeId;
|
||||||
location.value =
|
location.value =
|
||||||
store.getters["locations/getLocationById"](
|
store.getters["locations/getLocationById"](
|
||||||
event.extendedProps.locationId,
|
event.extendedProps.locationId,
|
||||||
) || null;
|
) || null;
|
||||||
|
|
||||||
console.log("new location value", location.value);
|
console.log("new location value", location.value);
|
||||||
console.log("calendar range id", calendarRangeId.value);
|
console.log("calendar range id", calendarRangeId.value);
|
||||||
showModal.value = true;
|
showModal.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveAndClose = function (e: Event): void {
|
const saveAndClose = function (e: Event): void {
|
||||||
console.log("saveEditAndClose", e);
|
console.log("saveEditAndClose", e);
|
||||||
|
|
||||||
store
|
store
|
||||||
.dispatch("calendarRanges/patchRangeLocation", {
|
.dispatch("calendarRanges/patchRangeLocation", {
|
||||||
location: location.value,
|
location: location.value,
|
||||||
calendarRangeId: calendarRangeId.value,
|
calendarRangeId: calendarRangeId.value,
|
||||||
})
|
})
|
||||||
.then((_) => {
|
.then((_) => {
|
||||||
showModal.value = false;
|
showModal.value = false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeModal = function (_: any): void {
|
const closeModal = function (_: any): void {
|
||||||
showModal.value = false;
|
showModal.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
defineExpose({ startEdit });
|
defineExpose({ startEdit });
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
const appMessages = {
|
const appMessages = {
|
||||||
fr: {
|
fr: {
|
||||||
created_availabilities: "Lieu des plages de disponibilités créées",
|
created_availabilities: "Lieu des plages de disponibilités créées",
|
||||||
edit_your_calendar_range: "Planifiez vos plages de disponibilités",
|
edit_your_calendar_range: "Planifiez vos plages de disponibilités",
|
||||||
show_my_calendar: "Afficher mon calendrier",
|
show_my_calendar: "Afficher mon calendrier",
|
||||||
show_weekends: "Afficher les week-ends",
|
show_weekends: "Afficher les week-ends",
|
||||||
copy_range: "Copier",
|
copy_range: "Copier",
|
||||||
copy_range_from_to: "Copier les plages",
|
copy_range_from_to: "Copier les plages",
|
||||||
from_day_to_day: "d'un jour à l'autre",
|
from_day_to_day: "d'un jour à l'autre",
|
||||||
from_week_to_week: "d'une semaine à l'autre",
|
from_week_to_week: "d'une semaine à l'autre",
|
||||||
copy_range_how_to:
|
copy_range_how_to:
|
||||||
"Créez les plages de disponibilités durant une journée et copiez-les facilement au jour suivant avec ce bouton. Si les week-ends sont cachés, le jour suivant un vendredi sera le lundi.",
|
"Créez les plages de disponibilités durant une journée et copiez-les facilement au jour suivant avec ce bouton. Si les week-ends sont cachés, le jour suivant un vendredi sera le lundi.",
|
||||||
new_range_to_save: "Nouvelles plages à enregistrer",
|
new_range_to_save: "Nouvelles plages à enregistrer",
|
||||||
update_range_to_save: "Plages à modifier",
|
update_range_to_save: "Plages à modifier",
|
||||||
delete_range_to_save: "Plages à supprimer",
|
delete_range_to_save: "Plages à supprimer",
|
||||||
by: "Par",
|
by: "Par",
|
||||||
main_user_concerned: "Utilisateur concerné",
|
main_user_concerned: "Utilisateur concerné",
|
||||||
dateFrom: "De",
|
dateFrom: "De",
|
||||||
dateTo: "à",
|
dateTo: "à",
|
||||||
day: "Jour",
|
day: "Jour",
|
||||||
week: "Semaine",
|
week: "Semaine",
|
||||||
month: "Mois",
|
month: "Mois",
|
||||||
today: "Aujourd'hui",
|
today: "Aujourd'hui",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export { appMessages };
|
export { appMessages };
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ import App2 from "./App2.vue";
|
|||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
futureStore().then((store) => {
|
futureStore().then((store) => {
|
||||||
const i18n = _createI18n(appMessages, false);
|
const i18n = _createI18n(appMessages, false);
|
||||||
|
|
||||||
const app = createApp({
|
const app = createApp({
|
||||||
template: `<app></app>`,
|
template: `<app></app>`,
|
||||||
})
|
})
|
||||||
.use(store, key)
|
.use(store, key)
|
||||||
.use(i18n)
|
.use(i18n)
|
||||||
.component("app", App2)
|
.component("app", App2)
|
||||||
.mount("#myCalendar");
|
.mount("#myCalendar");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import me, { MeState } from "./modules/me";
|
|||||||
import fullCalendar, { FullCalendarState } from "./modules/fullcalendar";
|
import fullCalendar, { FullCalendarState } from "./modules/fullcalendar";
|
||||||
import calendarRanges, { CalendarRangesState } from "./modules/calendarRanges";
|
import calendarRanges, { CalendarRangesState } from "./modules/calendarRanges";
|
||||||
import calendarRemotes, {
|
import calendarRemotes, {
|
||||||
CalendarRemotesState,
|
CalendarRemotesState,
|
||||||
} from "./modules/calendarRemotes";
|
} from "./modules/calendarRemotes";
|
||||||
import { whoami } from "../../../../../../ChillMainBundle/Resources/public/lib/api/user";
|
import { whoami } from "../../../../../../ChillMainBundle/Resources/public/lib/api/user";
|
||||||
import { User } from "../../../../../../ChillMainBundle/Resources/public/types";
|
import { User } from "../../../../../../ChillMainBundle/Resources/public/types";
|
||||||
@@ -15,40 +15,42 @@ import calendarLocals, { CalendarLocalsState } from "./modules/calendarLocals";
|
|||||||
const debug = process.env.NODE_ENV !== "production";
|
const debug = process.env.NODE_ENV !== "production";
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
calendarRanges: CalendarRangesState;
|
calendarRanges: CalendarRangesState;
|
||||||
calendarRemotes: CalendarRemotesState;
|
calendarRemotes: CalendarRemotesState;
|
||||||
calendarLocals: CalendarLocalsState;
|
calendarLocals: CalendarLocalsState;
|
||||||
fullCalendar: FullCalendarState;
|
fullCalendar: FullCalendarState;
|
||||||
me: MeState;
|
me: MeState;
|
||||||
locations: LocationState;
|
locations: LocationState;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const key: InjectionKey<Store<State>> = Symbol();
|
export const key: InjectionKey<Store<State>> = Symbol();
|
||||||
|
|
||||||
const futureStore = function (): Promise<Store<State>> {
|
const futureStore = function (): Promise<Store<State>> {
|
||||||
return whoami().then((user: User) => {
|
return whoami().then((user: User) => {
|
||||||
const store = createStore<State>({
|
const store = createStore<State>({
|
||||||
strict: debug,
|
strict: debug,
|
||||||
modules: {
|
modules: {
|
||||||
me,
|
me,
|
||||||
fullCalendar,
|
fullCalendar,
|
||||||
calendarRanges,
|
calendarRanges,
|
||||||
calendarRemotes,
|
calendarRemotes,
|
||||||
calendarLocals,
|
calendarLocals,
|
||||||
locations,
|
locations,
|
||||||
},
|
},
|
||||||
mutations: {},
|
mutations: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
store.commit("me/setWhoAmi", user, { root: true });
|
store.commit("me/setWhoAmi", user, { root: true });
|
||||||
store.dispatch("locations/getLocations", null, { root: true }).then((_) => {
|
store
|
||||||
return store.dispatch("locations/getCurrentLocation", null, {
|
.dispatch("locations/getLocations", null, { root: true })
|
||||||
root: true,
|
.then((_) => {
|
||||||
});
|
return store.dispatch("locations/getCurrentLocation", null, {
|
||||||
});
|
root: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return Promise.resolve(store);
|
return Promise.resolve(store);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default futureStore;
|
export default futureStore;
|
||||||
|
|||||||
@@ -8,99 +8,109 @@ import { TransportExceptionInterface } from "../../../../../../../ChillMainBundl
|
|||||||
import { COLORS } from "../../../Calendar/const";
|
import { COLORS } from "../../../Calendar/const";
|
||||||
|
|
||||||
export interface CalendarLocalsState {
|
export interface CalendarLocalsState {
|
||||||
locals: EventInput[];
|
locals: EventInput[];
|
||||||
localsLoaded: { start: number; end: number }[];
|
localsLoaded: { start: number; end: number }[];
|
||||||
localsIndex: Set<string>;
|
localsIndex: Set<string>;
|
||||||
key: number;
|
key: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Context = ActionContext<CalendarLocalsState, State>;
|
type Context = ActionContext<CalendarLocalsState, State>;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: (): CalendarLocalsState => ({
|
state: (): CalendarLocalsState => ({
|
||||||
locals: [],
|
locals: [],
|
||||||
localsLoaded: [],
|
localsLoaded: [],
|
||||||
localsIndex: new Set<string>(),
|
localsIndex: new Set<string>(),
|
||||||
key: 0,
|
key: 0,
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
isLocalsLoaded:
|
isLocalsLoaded:
|
||||||
(state: CalendarLocalsState) =>
|
(state: CalendarLocalsState) =>
|
||||||
({ start, end }: { start: Date; end: Date }): boolean => {
|
({ start, end }: { start: Date; end: Date }): boolean => {
|
||||||
for (const range of state.localsLoaded) {
|
for (const range of state.localsLoaded) {
|
||||||
if (start.getTime() === range.start && end.getTime() === range.end) {
|
if (
|
||||||
return true;
|
start.getTime() === range.start &&
|
||||||
}
|
end.getTime() === range.end
|
||||||
}
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
},
|
|
||||||
mutations: {
|
|
||||||
addLocals(state: CalendarLocalsState, ranges: CalendarLight[]) {
|
|
||||||
console.log("addLocals", ranges);
|
|
||||||
|
|
||||||
const toAdd = ranges
|
|
||||||
.map((cr) => localsToFullCalendarEvent(cr))
|
|
||||||
.filter((r) => !state.localsIndex.has(r.id));
|
|
||||||
|
|
||||||
toAdd.forEach((r) => {
|
|
||||||
state.localsIndex.add(r.id);
|
|
||||||
state.locals.push(r);
|
|
||||||
});
|
|
||||||
state.key = state.key + toAdd.length;
|
|
||||||
},
|
},
|
||||||
addLoaded(state: CalendarLocalsState, payload: { start: Date; end: Date }) {
|
mutations: {
|
||||||
state.localsLoaded.push({
|
addLocals(state: CalendarLocalsState, ranges: CalendarLight[]) {
|
||||||
start: payload.start.getTime(),
|
console.log("addLocals", ranges);
|
||||||
end: payload.end.getTime(),
|
|
||||||
});
|
const toAdd = ranges
|
||||||
|
.map((cr) => localsToFullCalendarEvent(cr))
|
||||||
|
.filter((r) => !state.localsIndex.has(r.id));
|
||||||
|
|
||||||
|
toAdd.forEach((r) => {
|
||||||
|
state.localsIndex.add(r.id);
|
||||||
|
state.locals.push(r);
|
||||||
|
});
|
||||||
|
state.key = state.key + toAdd.length;
|
||||||
|
},
|
||||||
|
addLoaded(
|
||||||
|
state: CalendarLocalsState,
|
||||||
|
payload: { start: Date; end: Date },
|
||||||
|
) {
|
||||||
|
state.localsLoaded.push({
|
||||||
|
start: payload.start.getTime(),
|
||||||
|
end: payload.end.getTime(),
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
actions: {
|
||||||
actions: {
|
fetchLocals(
|
||||||
fetchLocals(
|
ctx: Context,
|
||||||
ctx: Context,
|
payload: { start: Date; end: Date },
|
||||||
payload: { start: Date; end: Date },
|
): Promise<null> {
|
||||||
): Promise<null> {
|
const start = payload.start;
|
||||||
const start = payload.start;
|
const end = payload.end;
|
||||||
const end = payload.end;
|
|
||||||
|
|
||||||
if (ctx.rootGetters["me/getMe"] === null) {
|
if (ctx.rootGetters["me/getMe"] === null) {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.getters.isLocalsLoaded({ start, end })) {
|
if (ctx.getters.isLocalsLoaded({ start, end })) {
|
||||||
return Promise.resolve(ctx.getters.getRangeSource);
|
return Promise.resolve(ctx.getters.getRangeSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.commit("addLoaded", {
|
ctx.commit("addLoaded", {
|
||||||
start: start,
|
start: start,
|
||||||
end: end,
|
end: end,
|
||||||
});
|
});
|
||||||
|
|
||||||
return fetchCalendarLocalForUser(ctx.rootGetters["me/getMe"], start, end)
|
return fetchCalendarLocalForUser(
|
||||||
.then((remotes: CalendarLight[]) => {
|
ctx.rootGetters["me/getMe"],
|
||||||
// to be add when reactivity problem will be solve ?
|
start,
|
||||||
//ctx.commit('addRemotes', remotes);
|
end,
|
||||||
const inputs = remotes
|
)
|
||||||
.map((cr) => localsToFullCalendarEvent(cr))
|
.then((remotes: CalendarLight[]) => {
|
||||||
.map((cr) => ({
|
// to be add when reactivity problem will be solve ?
|
||||||
...cr,
|
//ctx.commit('addRemotes', remotes);
|
||||||
backgroundColor: COLORS[0],
|
const inputs = remotes
|
||||||
textColor: "black",
|
.map((cr) => localsToFullCalendarEvent(cr))
|
||||||
editable: false,
|
.map((cr) => ({
|
||||||
}));
|
...cr,
|
||||||
ctx.commit("calendarRanges/addExternals", inputs, {
|
backgroundColor: COLORS[0],
|
||||||
root: true,
|
textColor: "black",
|
||||||
});
|
editable: false,
|
||||||
return Promise.resolve(null);
|
}));
|
||||||
})
|
ctx.commit("calendarRanges/addExternals", inputs, {
|
||||||
.catch((e: TransportExceptionInterface) => {
|
root: true,
|
||||||
console.error(e);
|
});
|
||||||
|
return Promise.resolve(null);
|
||||||
|
})
|
||||||
|
.catch((e: TransportExceptionInterface) => {
|
||||||
|
console.error(e);
|
||||||
|
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
});
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
} as Module<CalendarLocalsState, State>;
|
} as Module<CalendarLocalsState, State>;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { State } from "./../index";
|
import { State } from "./../index";
|
||||||
import { ActionContext, Module } from "vuex";
|
import { ActionContext, Module } from "vuex";
|
||||||
import {
|
import {
|
||||||
CalendarRange,
|
CalendarRange,
|
||||||
CalendarRangeCreate,
|
CalendarRangeCreate,
|
||||||
CalendarRangeEdit,
|
CalendarRangeEdit,
|
||||||
isEventInputCalendarRange,
|
isEventInputCalendarRange,
|
||||||
} from "../../../../types";
|
} from "../../../../types";
|
||||||
import { Location } from "../../../../../../../ChillMainBundle/Resources/public/types";
|
import { Location } from "../../../../../../../ChillMainBundle/Resources/public/types";
|
||||||
import { fetchCalendarRangeForUser } from "../../../Calendar/api";
|
import { fetchCalendarRangeForUser } from "../../../Calendar/api";
|
||||||
@@ -12,332 +12,369 @@ import { calendarRangeToFullCalendarEvent } from "../../../Calendar/store/utils"
|
|||||||
import { EventInput } from "@fullcalendar/core";
|
import { EventInput } from "@fullcalendar/core";
|
||||||
import { makeFetch } from "../../../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
|
import { makeFetch } from "../../../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
|
||||||
import {
|
import {
|
||||||
datetimeToISO,
|
datetimeToISO,
|
||||||
dateToISO,
|
dateToISO,
|
||||||
ISOToDatetime,
|
ISOToDatetime,
|
||||||
} from "../../../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
} from "../../../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
||||||
import type { EventInputCalendarRange } from "../../../../types";
|
import type { EventInputCalendarRange } from "../../../../types";
|
||||||
|
|
||||||
export interface CalendarRangesState {
|
export interface CalendarRangesState {
|
||||||
ranges: (EventInput | EventInputCalendarRange)[];
|
ranges: (EventInput | EventInputCalendarRange)[];
|
||||||
rangesLoaded: { start: number; end: number }[];
|
rangesLoaded: { start: number; end: number }[];
|
||||||
rangesIndex: Set<string>;
|
rangesIndex: Set<string>;
|
||||||
key: number;
|
key: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Context = ActionContext<CalendarRangesState, State>;
|
type Context = ActionContext<CalendarRangesState, State>;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: (): CalendarRangesState => ({
|
state: (): CalendarRangesState => ({
|
||||||
ranges: [],
|
ranges: [],
|
||||||
rangesLoaded: [],
|
rangesLoaded: [],
|
||||||
rangesIndex: new Set<string>(),
|
rangesIndex: new Set<string>(),
|
||||||
key: 0,
|
key: 0,
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
isRangeLoaded:
|
isRangeLoaded:
|
||||||
(state: CalendarRangesState) =>
|
(state: CalendarRangesState) =>
|
||||||
({ start, end }: { start: Date; end: Date }): boolean => {
|
({ start, end }: { start: Date; end: Date }): boolean => {
|
||||||
for (const range of state.rangesLoaded) {
|
for (const range of state.rangesLoaded) {
|
||||||
if (start.getTime() === range.start && end.getTime() === range.end) {
|
if (
|
||||||
return true;
|
start.getTime() === range.start &&
|
||||||
}
|
end.getTime() === range.end
|
||||||
}
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
getRangesOnDate:
|
getRangesOnDate:
|
||||||
(state: CalendarRangesState) =>
|
(state: CalendarRangesState) =>
|
||||||
(date: Date): EventInputCalendarRange[] => {
|
(date: Date): EventInputCalendarRange[] => {
|
||||||
const founds = [];
|
const founds = [];
|
||||||
const dateStr = dateToISO(date) as string;
|
const dateStr = dateToISO(date) as string;
|
||||||
|
|
||||||
for (const range of state.ranges) {
|
for (const range of state.ranges) {
|
||||||
if (
|
if (
|
||||||
isEventInputCalendarRange(range) &&
|
isEventInputCalendarRange(range) &&
|
||||||
range.start.startsWith(dateStr)
|
range.start.startsWith(dateStr)
|
||||||
) {
|
) {
|
||||||
founds.push(range);
|
founds.push(range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return founds;
|
return founds;
|
||||||
},
|
},
|
||||||
getRangesOnWeek:
|
getRangesOnWeek:
|
||||||
(state: CalendarRangesState) =>
|
(state: CalendarRangesState) =>
|
||||||
(mondayDate: Date): EventInputCalendarRange[] => {
|
(mondayDate: Date): EventInputCalendarRange[] => {
|
||||||
const founds = [];
|
const founds = [];
|
||||||
for (const d of Array.from(Array(7).keys())) {
|
for (const d of Array.from(Array(7).keys())) {
|
||||||
const dateOfWeek = new Date(mondayDate);
|
const dateOfWeek = new Date(mondayDate);
|
||||||
dateOfWeek.setDate(mondayDate.getDate() + d);
|
dateOfWeek.setDate(mondayDate.getDate() + d);
|
||||||
const dateStr = dateToISO(dateOfWeek) as string;
|
const dateStr = dateToISO(dateOfWeek) as string;
|
||||||
for (const range of state.ranges) {
|
for (const range of state.ranges) {
|
||||||
if (
|
if (
|
||||||
isEventInputCalendarRange(range) &&
|
isEventInputCalendarRange(range) &&
|
||||||
range.start.startsWith(dateStr)
|
range.start.startsWith(dateStr)
|
||||||
) {
|
) {
|
||||||
founds.push(range);
|
founds.push(range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return founds;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
addRanges(state: CalendarRangesState, ranges: CalendarRange[]) {
|
||||||
|
const toAdd = ranges
|
||||||
|
.map((cr) => calendarRangeToFullCalendarEvent(cr))
|
||||||
|
.map((cr) => ({
|
||||||
|
...cr,
|
||||||
|
backgroundColor: "white",
|
||||||
|
borderColor: "#3788d8",
|
||||||
|
textColor: "black",
|
||||||
|
}))
|
||||||
|
.filter((r) => !state.rangesIndex.has(r.id));
|
||||||
|
|
||||||
|
toAdd.forEach((r) => {
|
||||||
|
state.rangesIndex.add(r.id);
|
||||||
|
state.ranges.push(r);
|
||||||
|
});
|
||||||
|
state.key = state.key + toAdd.length;
|
||||||
|
},
|
||||||
|
addExternals(
|
||||||
|
state: CalendarRangesState,
|
||||||
|
externalEvents: (EventInput & { id: string })[],
|
||||||
|
) {
|
||||||
|
const toAdd = externalEvents.filter(
|
||||||
|
(r) => !state.rangesIndex.has(r.id),
|
||||||
|
);
|
||||||
|
|
||||||
|
toAdd.forEach((r) => {
|
||||||
|
state.rangesIndex.add(r.id);
|
||||||
|
state.ranges.push(r);
|
||||||
|
});
|
||||||
|
state.key = state.key + toAdd.length;
|
||||||
|
},
|
||||||
|
addLoaded(
|
||||||
|
state: CalendarRangesState,
|
||||||
|
payload: { start: Date; end: Date },
|
||||||
|
) {
|
||||||
|
state.rangesLoaded.push({
|
||||||
|
start: payload.start.getTime(),
|
||||||
|
end: payload.end.getTime(),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addRange(state: CalendarRangesState, payload: CalendarRange) {
|
||||||
|
const asEvent = calendarRangeToFullCalendarEvent(payload);
|
||||||
|
state.ranges.push({
|
||||||
|
...asEvent,
|
||||||
|
backgroundColor: "white",
|
||||||
|
borderColor: "#3788d8",
|
||||||
|
textColor: "black",
|
||||||
|
});
|
||||||
|
state.rangesIndex.add(asEvent.id);
|
||||||
|
state.key = state.key + 1;
|
||||||
|
},
|
||||||
|
removeRange(state: CalendarRangesState, calendarRangeId: number) {
|
||||||
|
const found = state.ranges.find(
|
||||||
|
(r) =>
|
||||||
|
r.calendarRangeId === calendarRangeId && r.is === "range",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (found !== undefined) {
|
||||||
|
state.ranges = state.ranges.filter(
|
||||||
|
(r) =>
|
||||||
|
!(
|
||||||
|
r.calendarRangeId === calendarRangeId &&
|
||||||
|
r.is === "range"
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (typeof found.id === "string") {
|
||||||
|
// should always be true
|
||||||
|
state.rangesIndex.delete(found.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.key = state.key + 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return founds;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mutations: {
|
|
||||||
addRanges(state: CalendarRangesState, ranges: CalendarRange[]) {
|
|
||||||
const toAdd = ranges
|
|
||||||
.map((cr) => calendarRangeToFullCalendarEvent(cr))
|
|
||||||
.map((cr) => ({
|
|
||||||
...cr,
|
|
||||||
backgroundColor: "white",
|
|
||||||
borderColor: "#3788d8",
|
|
||||||
textColor: "black",
|
|
||||||
}))
|
|
||||||
.filter((r) => !state.rangesIndex.has(r.id));
|
|
||||||
|
|
||||||
toAdd.forEach((r) => {
|
|
||||||
state.rangesIndex.add(r.id);
|
|
||||||
state.ranges.push(r);
|
|
||||||
});
|
|
||||||
state.key = state.key + toAdd.length;
|
|
||||||
},
|
|
||||||
addExternals(
|
|
||||||
state: CalendarRangesState,
|
|
||||||
externalEvents: (EventInput & { id: string })[],
|
|
||||||
) {
|
|
||||||
const toAdd = externalEvents.filter((r) => !state.rangesIndex.has(r.id));
|
|
||||||
|
|
||||||
toAdd.forEach((r) => {
|
|
||||||
state.rangesIndex.add(r.id);
|
|
||||||
state.ranges.push(r);
|
|
||||||
});
|
|
||||||
state.key = state.key + toAdd.length;
|
|
||||||
},
|
|
||||||
addLoaded(state: CalendarRangesState, payload: { start: Date; end: Date }) {
|
|
||||||
state.rangesLoaded.push({
|
|
||||||
start: payload.start.getTime(),
|
|
||||||
end: payload.end.getTime(),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
addRange(state: CalendarRangesState, payload: CalendarRange) {
|
|
||||||
const asEvent = calendarRangeToFullCalendarEvent(payload);
|
|
||||||
state.ranges.push({
|
|
||||||
...asEvent,
|
|
||||||
backgroundColor: "white",
|
|
||||||
borderColor: "#3788d8",
|
|
||||||
textColor: "black",
|
|
||||||
});
|
|
||||||
state.rangesIndex.add(asEvent.id);
|
|
||||||
state.key = state.key + 1;
|
|
||||||
},
|
|
||||||
removeRange(state: CalendarRangesState, calendarRangeId: number) {
|
|
||||||
const found = state.ranges.find(
|
|
||||||
(r) => r.calendarRangeId === calendarRangeId && r.is === "range",
|
|
||||||
);
|
|
||||||
|
|
||||||
if (found !== undefined) {
|
|
||||||
state.ranges = state.ranges.filter(
|
|
||||||
(r) => !(r.calendarRangeId === calendarRangeId && r.is === "range"),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (typeof found.id === "string") {
|
|
||||||
// should always be true
|
|
||||||
state.rangesIndex.delete(found.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.key = state.key + 1;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
updateRange(state: CalendarRangesState, range: CalendarRange) {
|
|
||||||
const found = state.ranges.find(
|
|
||||||
(r) => r.calendarRangeId === range.id && r.is === "range",
|
|
||||||
);
|
|
||||||
const newEvent = calendarRangeToFullCalendarEvent(range);
|
|
||||||
|
|
||||||
if (found !== undefined) {
|
|
||||||
found.start = newEvent.start;
|
|
||||||
found.end = newEvent.end;
|
|
||||||
found.locationId = range.location.id;
|
|
||||||
found.locationName = range.location.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.key = state.key + 1;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
fetchRanges(
|
|
||||||
ctx: Context,
|
|
||||||
payload: { start: Date; end: Date },
|
|
||||||
): Promise<null> {
|
|
||||||
const start = payload.start;
|
|
||||||
const end = payload.end;
|
|
||||||
|
|
||||||
if (ctx.rootGetters["me/getMe"] === null) {
|
|
||||||
return Promise.resolve(ctx.getters.getRangeSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx.getters.isRangeLoaded({ start, end })) {
|
|
||||||
return Promise.resolve(ctx.getters.getRangeSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.commit("addLoaded", {
|
|
||||||
start: start,
|
|
||||||
end: end,
|
|
||||||
});
|
|
||||||
|
|
||||||
return fetchCalendarRangeForUser(
|
|
||||||
ctx.rootGetters["me/getMe"],
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
).then((ranges: CalendarRange[]) => {
|
|
||||||
ctx.commit("addRanges", ranges);
|
|
||||||
return Promise.resolve(null);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
createRange(
|
|
||||||
ctx: Context,
|
|
||||||
{ start, end, location }: { start: Date; end: Date; location: Location },
|
|
||||||
): Promise<null> {
|
|
||||||
const url = `/api/1.0/calendar/calendar-range.json?`;
|
|
||||||
|
|
||||||
if (ctx.rootState.me.me === null) {
|
|
||||||
throw new Error("user is currently null");
|
|
||||||
}
|
|
||||||
|
|
||||||
const body = {
|
|
||||||
user: {
|
|
||||||
id: ctx.rootState.me.me.id,
|
|
||||||
type: "user",
|
|
||||||
},
|
},
|
||||||
startDate: {
|
updateRange(state: CalendarRangesState, range: CalendarRange) {
|
||||||
datetime: datetimeToISO(start),
|
const found = state.ranges.find(
|
||||||
|
(r) => r.calendarRangeId === range.id && r.is === "range",
|
||||||
|
);
|
||||||
|
const newEvent = calendarRangeToFullCalendarEvent(range);
|
||||||
|
|
||||||
|
if (found !== undefined) {
|
||||||
|
found.start = newEvent.start;
|
||||||
|
found.end = newEvent.end;
|
||||||
|
found.locationId = range.location.id;
|
||||||
|
found.locationName = range.location.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.key = state.key + 1;
|
||||||
},
|
},
|
||||||
endDate: {
|
},
|
||||||
datetime: datetimeToISO(end),
|
actions: {
|
||||||
|
fetchRanges(
|
||||||
|
ctx: Context,
|
||||||
|
payload: { start: Date; end: Date },
|
||||||
|
): Promise<null> {
|
||||||
|
const start = payload.start;
|
||||||
|
const end = payload.end;
|
||||||
|
|
||||||
|
if (ctx.rootGetters["me/getMe"] === null) {
|
||||||
|
return Promise.resolve(ctx.getters.getRangeSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.getters.isRangeLoaded({ start, end })) {
|
||||||
|
return Promise.resolve(ctx.getters.getRangeSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.commit("addLoaded", {
|
||||||
|
start: start,
|
||||||
|
end: end,
|
||||||
|
});
|
||||||
|
|
||||||
|
return fetchCalendarRangeForUser(
|
||||||
|
ctx.rootGetters["me/getMe"],
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
).then((ranges: CalendarRange[]) => {
|
||||||
|
ctx.commit("addRanges", ranges);
|
||||||
|
return Promise.resolve(null);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
location: {
|
createRange(
|
||||||
id: location.id,
|
ctx: Context,
|
||||||
type: "location",
|
{
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
location,
|
||||||
|
}: { start: Date; end: Date; location: Location },
|
||||||
|
): Promise<null> {
|
||||||
|
const url = `/api/1.0/calendar/calendar-range.json?`;
|
||||||
|
|
||||||
|
if (ctx.rootState.me.me === null) {
|
||||||
|
throw new Error("user is currently null");
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
user: {
|
||||||
|
id: ctx.rootState.me.me.id,
|
||||||
|
type: "user",
|
||||||
|
},
|
||||||
|
startDate: {
|
||||||
|
datetime: datetimeToISO(start),
|
||||||
|
},
|
||||||
|
endDate: {
|
||||||
|
datetime: datetimeToISO(end),
|
||||||
|
},
|
||||||
|
location: {
|
||||||
|
id: location.id,
|
||||||
|
type: "location",
|
||||||
|
},
|
||||||
|
} as CalendarRangeCreate;
|
||||||
|
|
||||||
|
return makeFetch<CalendarRangeCreate, CalendarRange>(
|
||||||
|
"POST",
|
||||||
|
url,
|
||||||
|
body,
|
||||||
|
)
|
||||||
|
.then((newRange) => {
|
||||||
|
ctx.commit("addRange", newRange);
|
||||||
|
|
||||||
|
return Promise.resolve(null);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
} as CalendarRangeCreate;
|
deleteRange(ctx: Context, calendarRangeId: number) {
|
||||||
|
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
||||||
|
|
||||||
return makeFetch<CalendarRangeCreate, CalendarRange>("POST", url, body)
|
makeFetch<undefined, never>("DELETE", url).then(() => {
|
||||||
.then((newRange) => {
|
ctx.commit("removeRange", calendarRangeId);
|
||||||
ctx.commit("addRange", newRange);
|
});
|
||||||
|
|
||||||
return Promise.resolve(null);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error(error);
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
deleteRange(ctx: Context, calendarRangeId: number) {
|
|
||||||
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
|
||||||
|
|
||||||
makeFetch<undefined, never>("DELETE", url).then(() => {
|
|
||||||
ctx.commit("removeRange", calendarRangeId);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
patchRangeTime(
|
|
||||||
ctx,
|
|
||||||
{
|
|
||||||
calendarRangeId,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
}: { calendarRangeId: number; start: Date; end: Date },
|
|
||||||
): Promise<null> {
|
|
||||||
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
|
||||||
const body = {
|
|
||||||
startDate: {
|
|
||||||
datetime: datetimeToISO(start),
|
|
||||||
},
|
},
|
||||||
endDate: {
|
patchRangeTime(
|
||||||
datetime: datetimeToISO(end),
|
ctx,
|
||||||
|
{
|
||||||
|
calendarRangeId,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
}: { calendarRangeId: number; start: Date; end: Date },
|
||||||
|
): Promise<null> {
|
||||||
|
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
||||||
|
const body = {
|
||||||
|
startDate: {
|
||||||
|
datetime: datetimeToISO(start),
|
||||||
|
},
|
||||||
|
endDate: {
|
||||||
|
datetime: datetimeToISO(end),
|
||||||
|
},
|
||||||
|
} as CalendarRangeEdit;
|
||||||
|
|
||||||
|
return makeFetch<CalendarRangeEdit, CalendarRange>(
|
||||||
|
"PATCH",
|
||||||
|
url,
|
||||||
|
body,
|
||||||
|
)
|
||||||
|
.then((range) => {
|
||||||
|
ctx.commit("updateRange", range);
|
||||||
|
return Promise.resolve(null);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
return Promise.resolve(null);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
} as CalendarRangeEdit;
|
patchRangeLocation(
|
||||||
|
ctx,
|
||||||
|
{
|
||||||
|
location,
|
||||||
|
calendarRangeId,
|
||||||
|
}: { location: Location; calendarRangeId: number },
|
||||||
|
): Promise<null> {
|
||||||
|
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
||||||
|
const body = {
|
||||||
|
location: {
|
||||||
|
id: location.id,
|
||||||
|
type: "location",
|
||||||
|
},
|
||||||
|
} as CalendarRangeEdit;
|
||||||
|
|
||||||
return makeFetch<CalendarRangeEdit, CalendarRange>("PATCH", url, body)
|
return makeFetch<CalendarRangeEdit, CalendarRange>(
|
||||||
.then((range) => {
|
"PATCH",
|
||||||
ctx.commit("updateRange", range);
|
url,
|
||||||
return Promise.resolve(null);
|
body,
|
||||||
})
|
)
|
||||||
.catch((error) => {
|
.then((range) => {
|
||||||
console.error(error);
|
ctx.commit("updateRange", range);
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
});
|
})
|
||||||
},
|
.catch((error) => {
|
||||||
patchRangeLocation(
|
console.error(error);
|
||||||
ctx,
|
return Promise.resolve(null);
|
||||||
{
|
});
|
||||||
location,
|
|
||||||
calendarRangeId,
|
|
||||||
}: { location: Location; calendarRangeId: number },
|
|
||||||
): Promise<null> {
|
|
||||||
const url = `/api/1.0/calendar/calendar-range/${calendarRangeId}.json`;
|
|
||||||
const body = {
|
|
||||||
location: {
|
|
||||||
id: location.id,
|
|
||||||
type: "location",
|
|
||||||
},
|
},
|
||||||
} as CalendarRangeEdit;
|
copyFromDayToAnotherDay(
|
||||||
|
ctx,
|
||||||
|
{ from, to }: { from: Date; to: Date },
|
||||||
|
): Promise<null> {
|
||||||
|
const rangesToCopy: EventInputCalendarRange[] =
|
||||||
|
ctx.getters["getRangesOnDate"](from);
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
return makeFetch<CalendarRangeEdit, CalendarRange>("PATCH", url, body)
|
for (const r of rangesToCopy) {
|
||||||
.then((range) => {
|
const start = new Date(ISOToDatetime(r.start) as Date);
|
||||||
ctx.commit("updateRange", range);
|
start.setFullYear(
|
||||||
return Promise.resolve(null);
|
to.getFullYear(),
|
||||||
})
|
to.getMonth(),
|
||||||
.catch((error) => {
|
to.getDate(),
|
||||||
console.error(error);
|
);
|
||||||
return Promise.resolve(null);
|
const end = new Date(ISOToDatetime(r.end) as Date);
|
||||||
});
|
end.setFullYear(to.getFullYear(), to.getMonth(), to.getDate());
|
||||||
|
const location = ctx.rootGetters["locations/getLocationById"](
|
||||||
|
r.locationId,
|
||||||
|
);
|
||||||
|
|
||||||
|
promises.push(
|
||||||
|
ctx.dispatch("createRange", { start, end, location }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(promises).then(() => Promise.resolve(null));
|
||||||
|
},
|
||||||
|
copyFromWeekToAnotherWeek(
|
||||||
|
ctx: Context,
|
||||||
|
{ fromMonday, toMonday }: { fromMonday: Date; toMonday: Date },
|
||||||
|
): Promise<null> {
|
||||||
|
const rangesToCopy: EventInputCalendarRange[] =
|
||||||
|
ctx.getters["getRangesOnWeek"](fromMonday);
|
||||||
|
const promises = [];
|
||||||
|
const diffTime = toMonday.getTime() - fromMonday.getTime();
|
||||||
|
for (const r of rangesToCopy) {
|
||||||
|
const start = new Date(ISOToDatetime(r.start) as Date);
|
||||||
|
const end = new Date(ISOToDatetime(r.end) as Date);
|
||||||
|
start.setTime(start.getTime() + diffTime);
|
||||||
|
end.setTime(end.getTime() + diffTime);
|
||||||
|
const location = ctx.rootGetters["locations/getLocationById"](
|
||||||
|
r.locationId,
|
||||||
|
);
|
||||||
|
|
||||||
|
promises.push(
|
||||||
|
ctx.dispatch("createRange", { start, end, location }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(promises).then(() => Promise.resolve(null));
|
||||||
|
},
|
||||||
},
|
},
|
||||||
copyFromDayToAnotherDay(
|
|
||||||
ctx,
|
|
||||||
{ from, to }: { from: Date; to: Date },
|
|
||||||
): Promise<null> {
|
|
||||||
const rangesToCopy: EventInputCalendarRange[] =
|
|
||||||
ctx.getters["getRangesOnDate"](from);
|
|
||||||
const promises = [];
|
|
||||||
|
|
||||||
for (const r of rangesToCopy) {
|
|
||||||
const start = new Date(ISOToDatetime(r.start) as Date);
|
|
||||||
start.setFullYear(to.getFullYear(), to.getMonth(), to.getDate());
|
|
||||||
const end = new Date(ISOToDatetime(r.end) as Date);
|
|
||||||
end.setFullYear(to.getFullYear(), to.getMonth(), to.getDate());
|
|
||||||
const location = ctx.rootGetters["locations/getLocationById"](
|
|
||||||
r.locationId,
|
|
||||||
);
|
|
||||||
|
|
||||||
promises.push(ctx.dispatch("createRange", { start, end, location }));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.all(promises).then(() => Promise.resolve(null));
|
|
||||||
},
|
|
||||||
copyFromWeekToAnotherWeek(
|
|
||||||
ctx: Context,
|
|
||||||
{ fromMonday, toMonday }: { fromMonday: Date; toMonday: Date },
|
|
||||||
): Promise<null> {
|
|
||||||
const rangesToCopy: EventInputCalendarRange[] =
|
|
||||||
ctx.getters["getRangesOnWeek"](fromMonday);
|
|
||||||
const promises = [];
|
|
||||||
const diffTime = toMonday.getTime() - fromMonday.getTime();
|
|
||||||
for (const r of rangesToCopy) {
|
|
||||||
const start = new Date(ISOToDatetime(r.start) as Date);
|
|
||||||
const end = new Date(ISOToDatetime(r.end) as Date);
|
|
||||||
start.setTime(start.getTime() + diffTime);
|
|
||||||
end.setTime(end.getTime() + diffTime);
|
|
||||||
const location = ctx.rootGetters["locations/getLocationById"](
|
|
||||||
r.locationId,
|
|
||||||
);
|
|
||||||
|
|
||||||
promises.push(ctx.dispatch("createRange", { start, end, location }));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.all(promises).then(() => Promise.resolve(null));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as Module<CalendarRangesState, State>;
|
} as Module<CalendarRangesState, State>;
|
||||||
|
|||||||
@@ -8,102 +8,109 @@ import { TransportExceptionInterface } from "../../../../../../../ChillMainBundl
|
|||||||
import { COLORS } from "../../../Calendar/const";
|
import { COLORS } from "../../../Calendar/const";
|
||||||
|
|
||||||
export interface CalendarRemotesState {
|
export interface CalendarRemotesState {
|
||||||
remotes: EventInput[];
|
remotes: EventInput[];
|
||||||
remotesLoaded: { start: number; end: number }[];
|
remotesLoaded: { start: number; end: number }[];
|
||||||
remotesIndex: Set<string>;
|
remotesIndex: Set<string>;
|
||||||
key: number;
|
key: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Context = ActionContext<CalendarRemotesState, State>;
|
type Context = ActionContext<CalendarRemotesState, State>;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: (): CalendarRemotesState => ({
|
state: (): CalendarRemotesState => ({
|
||||||
remotes: [],
|
remotes: [],
|
||||||
remotesLoaded: [],
|
remotesLoaded: [],
|
||||||
remotesIndex: new Set<string>(),
|
remotesIndex: new Set<string>(),
|
||||||
key: 0,
|
key: 0,
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
isRemotesLoaded:
|
isRemotesLoaded:
|
||||||
(state: CalendarRemotesState) =>
|
(state: CalendarRemotesState) =>
|
||||||
({ start, end }: { start: Date; end: Date }): boolean => {
|
({ start, end }: { start: Date; end: Date }): boolean => {
|
||||||
for (const range of state.remotesLoaded) {
|
for (const range of state.remotesLoaded) {
|
||||||
if (start.getTime() === range.start && end.getTime() === range.end) {
|
if (
|
||||||
return true;
|
start.getTime() === range.start &&
|
||||||
}
|
end.getTime() === range.end
|
||||||
}
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
},
|
|
||||||
mutations: {
|
|
||||||
addRemotes(state: CalendarRemotesState, ranges: CalendarRemote[]) {
|
|
||||||
console.log("addRemotes", ranges);
|
|
||||||
|
|
||||||
const toAdd = ranges
|
|
||||||
.map((cr) => remoteToFullCalendarEvent(cr))
|
|
||||||
.filter((r) => !state.remotesIndex.has(r.id));
|
|
||||||
|
|
||||||
toAdd.forEach((r) => {
|
|
||||||
state.remotesIndex.add(r.id);
|
|
||||||
state.remotes.push(r);
|
|
||||||
});
|
|
||||||
state.key = state.key + toAdd.length;
|
|
||||||
},
|
},
|
||||||
addLoaded(
|
mutations: {
|
||||||
state: CalendarRemotesState,
|
addRemotes(state: CalendarRemotesState, ranges: CalendarRemote[]) {
|
||||||
payload: { start: Date; end: Date },
|
console.log("addRemotes", ranges);
|
||||||
) {
|
|
||||||
state.remotesLoaded.push({
|
const toAdd = ranges
|
||||||
start: payload.start.getTime(),
|
.map((cr) => remoteToFullCalendarEvent(cr))
|
||||||
end: payload.end.getTime(),
|
.filter((r) => !state.remotesIndex.has(r.id));
|
||||||
});
|
|
||||||
|
toAdd.forEach((r) => {
|
||||||
|
state.remotesIndex.add(r.id);
|
||||||
|
state.remotes.push(r);
|
||||||
|
});
|
||||||
|
state.key = state.key + toAdd.length;
|
||||||
|
},
|
||||||
|
addLoaded(
|
||||||
|
state: CalendarRemotesState,
|
||||||
|
payload: { start: Date; end: Date },
|
||||||
|
) {
|
||||||
|
state.remotesLoaded.push({
|
||||||
|
start: payload.start.getTime(),
|
||||||
|
end: payload.end.getTime(),
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
actions: {
|
||||||
actions: {
|
fetchRemotes(
|
||||||
fetchRemotes(
|
ctx: Context,
|
||||||
ctx: Context,
|
payload: { start: Date; end: Date },
|
||||||
payload: { start: Date; end: Date },
|
): Promise<null> {
|
||||||
): Promise<null> {
|
const start = payload.start;
|
||||||
const start = payload.start;
|
const end = payload.end;
|
||||||
const end = payload.end;
|
|
||||||
|
|
||||||
if (ctx.rootGetters["me/getMe"] === null) {
|
if (ctx.rootGetters["me/getMe"] === null) {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.getters.isRemotesLoaded({ start, end })) {
|
if (ctx.getters.isRemotesLoaded({ start, end })) {
|
||||||
return Promise.resolve(ctx.getters.getRangeSource);
|
return Promise.resolve(ctx.getters.getRangeSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.commit("addLoaded", {
|
ctx.commit("addLoaded", {
|
||||||
start: start,
|
start: start,
|
||||||
end: end,
|
end: end,
|
||||||
});
|
});
|
||||||
|
|
||||||
return fetchCalendarRemoteForUser(ctx.rootGetters["me/getMe"], start, end)
|
return fetchCalendarRemoteForUser(
|
||||||
.then((remotes: CalendarRemote[]) => {
|
ctx.rootGetters["me/getMe"],
|
||||||
// to be add when reactivity problem will be solve ?
|
start,
|
||||||
//ctx.commit('addRemotes', remotes);
|
end,
|
||||||
const inputs = remotes
|
)
|
||||||
.map((cr) => remoteToFullCalendarEvent(cr))
|
.then((remotes: CalendarRemote[]) => {
|
||||||
.map((cr) => ({
|
// to be add when reactivity problem will be solve ?
|
||||||
...cr,
|
//ctx.commit('addRemotes', remotes);
|
||||||
backgroundColor: COLORS[0],
|
const inputs = remotes
|
||||||
textColor: "black",
|
.map((cr) => remoteToFullCalendarEvent(cr))
|
||||||
editable: false,
|
.map((cr) => ({
|
||||||
}));
|
...cr,
|
||||||
ctx.commit("calendarRanges/addExternals", inputs, {
|
backgroundColor: COLORS[0],
|
||||||
root: true,
|
textColor: "black",
|
||||||
});
|
editable: false,
|
||||||
return Promise.resolve(null);
|
}));
|
||||||
})
|
ctx.commit("calendarRanges/addExternals", inputs, {
|
||||||
.catch((e: TransportExceptionInterface) => {
|
root: true,
|
||||||
console.error(e);
|
});
|
||||||
|
return Promise.resolve(null);
|
||||||
|
})
|
||||||
|
.catch((e: TransportExceptionInterface) => {
|
||||||
|
console.error(e);
|
||||||
|
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
});
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
} as Module<CalendarRemotesState, State>;
|
} as Module<CalendarRemotesState, State>;
|
||||||
|
|||||||
@@ -2,77 +2,77 @@ import { State } from "./../index";
|
|||||||
import { ActionContext } from "vuex";
|
import { ActionContext } from "vuex";
|
||||||
|
|
||||||
export interface FullCalendarState {
|
export interface FullCalendarState {
|
||||||
currentView: {
|
currentView: {
|
||||||
start: Date | null;
|
start: Date | null;
|
||||||
end: Date | null;
|
end: Date | null;
|
||||||
};
|
};
|
||||||
key: number;
|
key: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Context = ActionContext<FullCalendarState, State>;
|
type Context = ActionContext<FullCalendarState, State>;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: (): FullCalendarState => ({
|
state: (): FullCalendarState => ({
|
||||||
currentView: {
|
currentView: {
|
||||||
start: null,
|
start: null,
|
||||||
end: null,
|
end: null,
|
||||||
|
},
|
||||||
|
key: 0,
|
||||||
|
}),
|
||||||
|
mutations: {
|
||||||
|
setCurrentDatesView: function (
|
||||||
|
state: FullCalendarState,
|
||||||
|
payload: { start: Date; end: Date },
|
||||||
|
): void {
|
||||||
|
state.currentView.start = payload.start;
|
||||||
|
state.currentView.end = payload.end;
|
||||||
|
},
|
||||||
|
increaseKey: function (state: FullCalendarState): void {
|
||||||
|
state.key = state.key + 1;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
key: 0,
|
actions: {
|
||||||
}),
|
setCurrentDatesView(
|
||||||
mutations: {
|
ctx: Context,
|
||||||
setCurrentDatesView: function (
|
{ start, end }: { start: Date | null; end: Date | null },
|
||||||
state: FullCalendarState,
|
): Promise<null> {
|
||||||
payload: { start: Date; end: Date },
|
console.log("dispatch setCurrentDatesView", { start, end });
|
||||||
): void {
|
|
||||||
state.currentView.start = payload.start;
|
|
||||||
state.currentView.end = payload.end;
|
|
||||||
},
|
|
||||||
increaseKey: function (state: FullCalendarState): void {
|
|
||||||
state.key = state.key + 1;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
setCurrentDatesView(
|
|
||||||
ctx: Context,
|
|
||||||
{ start, end }: { start: Date | null; end: Date | null },
|
|
||||||
): Promise<null> {
|
|
||||||
console.log("dispatch setCurrentDatesView", { start, end });
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
ctx.state.currentView.start !== start ||
|
ctx.state.currentView.start !== start ||
|
||||||
ctx.state.currentView.end !== end
|
ctx.state.currentView.end !== end
|
||||||
) {
|
) {
|
||||||
ctx.commit("setCurrentDatesView", { start, end });
|
ctx.commit("setCurrentDatesView", { start, end });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start !== null && end !== null) {
|
if (start !== null && end !== null) {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
ctx
|
ctx
|
||||||
.dispatch(
|
.dispatch(
|
||||||
"calendarRanges/fetchRanges",
|
"calendarRanges/fetchRanges",
|
||||||
{ start, end },
|
{ start, end },
|
||||||
{ root: true },
|
{ root: true },
|
||||||
)
|
)
|
||||||
.then((_) => Promise.resolve(null)),
|
.then((_) => Promise.resolve(null)),
|
||||||
ctx
|
ctx
|
||||||
.dispatch(
|
.dispatch(
|
||||||
"calendarRemotes/fetchRemotes",
|
"calendarRemotes/fetchRemotes",
|
||||||
{ start, end },
|
{ start, end },
|
||||||
{ root: true },
|
{ root: true },
|
||||||
)
|
)
|
||||||
.then((_) => Promise.resolve(null)),
|
.then((_) => Promise.resolve(null)),
|
||||||
ctx
|
ctx
|
||||||
.dispatch(
|
.dispatch(
|
||||||
"calendarLocals/fetchLocals",
|
"calendarLocals/fetchLocals",
|
||||||
{ start, end },
|
{ start, end },
|
||||||
{ root: true },
|
{ root: true },
|
||||||
)
|
)
|
||||||
.then((_) => Promise.resolve(null)),
|
.then((_) => Promise.resolve(null)),
|
||||||
]).then((_) => Promise.resolve(null));
|
]).then((_) => Promise.resolve(null));
|
||||||
} else {
|
} else {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,61 +5,61 @@ import { getLocations } from "../../../../../../../ChillMainBundle/Resources/pub
|
|||||||
import { whereami } from "../../../../../../../ChillMainBundle/Resources/public/lib/api/user";
|
import { whereami } from "../../../../../../../ChillMainBundle/Resources/public/lib/api/user";
|
||||||
|
|
||||||
export interface LocationState {
|
export interface LocationState {
|
||||||
locations: Location[];
|
locations: Location[];
|
||||||
locationPicked: Location | null;
|
locationPicked: Location | null;
|
||||||
currentLocation: Location | null;
|
currentLocation: Location | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: (): LocationState => {
|
state: (): LocationState => {
|
||||||
return {
|
return {
|
||||||
locations: [],
|
locations: [],
|
||||||
locationPicked: null,
|
locationPicked: null,
|
||||||
currentLocation: null,
|
currentLocation: null,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
getters: {
|
|
||||||
getLocationById:
|
|
||||||
(state) =>
|
|
||||||
(id: number): Location | undefined => {
|
|
||||||
return state.locations.find((l) => l.id === id);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mutations: {
|
|
||||||
setLocations(state, locations): void {
|
|
||||||
state.locations = locations;
|
|
||||||
},
|
},
|
||||||
setLocationPicked(state, location: Location | null): void {
|
getters: {
|
||||||
if (null === location) {
|
getLocationById:
|
||||||
state.locationPicked = null;
|
(state) =>
|
||||||
return;
|
(id: number): Location | undefined => {
|
||||||
}
|
return state.locations.find((l) => l.id === id);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
setLocations(state, locations): void {
|
||||||
|
state.locations = locations;
|
||||||
|
},
|
||||||
|
setLocationPicked(state, location: Location | null): void {
|
||||||
|
if (null === location) {
|
||||||
|
state.locationPicked = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
state.locationPicked =
|
state.locationPicked =
|
||||||
state.locations.find((l) => l.id === location.id) || null;
|
state.locations.find((l) => l.id === location.id) || null;
|
||||||
},
|
},
|
||||||
setCurrentLocation(state, location: Location | null): void {
|
setCurrentLocation(state, location: Location | null): void {
|
||||||
if (null === location) {
|
if (null === location) {
|
||||||
state.currentLocation = null;
|
state.currentLocation = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.currentLocation =
|
state.currentLocation =
|
||||||
state.locations.find((l) => l.id === location.id) || null;
|
state.locations.find((l) => l.id === location.id) || null;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
actions: {
|
||||||
actions: {
|
getLocations(ctx): Promise<void> {
|
||||||
getLocations(ctx): Promise<void> {
|
return getLocations().then((locations) => {
|
||||||
return getLocations().then((locations) => {
|
ctx.commit("setLocations", locations);
|
||||||
ctx.commit("setLocations", locations);
|
return Promise.resolve();
|
||||||
return Promise.resolve();
|
});
|
||||||
});
|
},
|
||||||
|
getCurrentLocation(ctx): Promise<void> {
|
||||||
|
return whereami().then((location) => {
|
||||||
|
ctx.commit("setCurrentLocation", location);
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
getCurrentLocation(ctx): Promise<void> {
|
|
||||||
return whereami().then((location) => {
|
|
||||||
ctx.commit("setCurrentLocation", location);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as Module<LocationState, State>;
|
} as Module<LocationState, State>;
|
||||||
|
|||||||
@@ -3,24 +3,24 @@ import { User } from "../../../../../../../ChillMainBundle/Resources/public/type
|
|||||||
import { ActionContext } from "vuex";
|
import { ActionContext } from "vuex";
|
||||||
|
|
||||||
export interface MeState {
|
export interface MeState {
|
||||||
me: User | null;
|
me: User | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Context = ActionContext<MeState, State>;
|
type Context = ActionContext<MeState, State>;
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
state: (): MeState => ({
|
state: (): MeState => ({
|
||||||
me: null,
|
me: null,
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
getMe: function (state: MeState): User | null {
|
getMe: function (state: MeState): User | null {
|
||||||
return state.me;
|
return state.me;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
mutations: {
|
||||||
mutations: {
|
setWhoAmi(state: MeState, me: User) {
|
||||||
setWhoAmi(state: MeState, me: User) {
|
state.me = me;
|
||||||
state.me = me;
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h2 class="chill-red">
|
<h2 class="chill-red">
|
||||||
{{ $t("choose_your_calendar_user") }}
|
{{ $t("choose_your_calendar_user") }}
|
||||||
</h2>
|
</h2>
|
||||||
<VueMultiselect
|
<VueMultiselect
|
||||||
name="field"
|
name="field"
|
||||||
id="calendarUserSelector"
|
id="calendarUserSelector"
|
||||||
v-model="value"
|
v-model="value"
|
||||||
track-by="id"
|
track-by="id"
|
||||||
label="value"
|
label="value"
|
||||||
:custom-label="transName"
|
:custom-label="transName"
|
||||||
:placeholder="$t('select_user')"
|
:placeholder="$t('select_user')"
|
||||||
:multiple="true"
|
:multiple="true"
|
||||||
:close-on-select="false"
|
:close-on-select="false"
|
||||||
:allow-empty="true"
|
:allow-empty="true"
|
||||||
:model-value="value"
|
:model-value="value"
|
||||||
:select-label="$t('multiselect.select_label')"
|
:select-label="$t('multiselect.select_label')"
|
||||||
:deselect-label="$t('multiselect.deselect_label')"
|
:deselect-label="$t('multiselect.deselect_label')"
|
||||||
:selected-label="$t('multiselect.selected_label')"
|
:selected-label="$t('multiselect.selected_label')"
|
||||||
@select="selectUsers"
|
@select="selectUsers"
|
||||||
@remove="unSelectUsers"
|
@remove="unSelectUsers"
|
||||||
@close="coloriseSelectedValues"
|
@close="coloriseSelectedValues"
|
||||||
:options="options"
|
:options="options"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="myCalendar"
|
id="myCalendar"
|
||||||
class="form-check-input"
|
class="form-check-input"
|
||||||
v-model="showMyCalendarWidget"
|
v-model="showMyCalendarWidget"
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label" for="myCalendar">{{
|
<label class="form-check-label" for="myCalendar">{{
|
||||||
$t("show_my_calendar")
|
$t("show_my_calendar")
|
||||||
}}</label>
|
}}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="weekends"
|
id="weekends"
|
||||||
class="form-check-input"
|
class="form-check-input"
|
||||||
@click="toggleWeekends"
|
@click="toggleWeekends"
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label" for="weekends">{{
|
<label class="form-check-label" for="weekends">{{
|
||||||
$t("show_weekends")
|
$t("show_weekends")
|
||||||
}}</label>
|
}}</label>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { fetchCalendarRanges, fetchCalendar } from "../../_api/api";
|
import { fetchCalendarRanges, fetchCalendar } from "../../_api/api";
|
||||||
@@ -53,184 +53,205 @@ import VueMultiselect from "vue-multiselect";
|
|||||||
import { whoami } from "ChillPersonAssets/vuejs/AccompanyingCourse/api";
|
import { whoami } from "ChillPersonAssets/vuejs/AccompanyingCourse/api";
|
||||||
|
|
||||||
const COLORS = [
|
const COLORS = [
|
||||||
/* from https://colorbrewer2.org/#type=qualitative&scheme=Set3&n=12 */
|
/* from https://colorbrewer2.org/#type=qualitative&scheme=Set3&n=12 */
|
||||||
"#8dd3c7",
|
"#8dd3c7",
|
||||||
"#ffffb3",
|
"#ffffb3",
|
||||||
"#bebada",
|
"#bebada",
|
||||||
"#fb8072",
|
"#fb8072",
|
||||||
"#80b1d3",
|
"#80b1d3",
|
||||||
"#fdb462",
|
"#fdb462",
|
||||||
"#b3de69",
|
"#b3de69",
|
||||||
"#fccde5",
|
"#fccde5",
|
||||||
"#d9d9d9",
|
"#d9d9d9",
|
||||||
"#bc80bd",
|
"#bc80bd",
|
||||||
"#ccebc5",
|
"#ccebc5",
|
||||||
"#ffed6f",
|
"#ffed6f",
|
||||||
];
|
];
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "CalendarUserSelector",
|
name: "CalendarUserSelector",
|
||||||
components: { VueMultiselect },
|
components: { VueMultiselect },
|
||||||
props: [
|
props: [
|
||||||
"users",
|
"users",
|
||||||
"updateEventsSource",
|
"updateEventsSource",
|
||||||
"calendarEvents",
|
"calendarEvents",
|
||||||
"showMyCalendar",
|
"showMyCalendar",
|
||||||
"toggleMyCalendar",
|
"toggleMyCalendar",
|
||||||
"toggleWeekends",
|
"toggleWeekends",
|
||||||
],
|
],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
errorMsg: [],
|
errorMsg: [],
|
||||||
value: [],
|
value: [],
|
||||||
options: [],
|
options: [],
|
||||||
};
|
};
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
showMyCalendarWidget: {
|
|
||||||
set(value) {
|
|
||||||
this.toggleMyCalendar(value);
|
|
||||||
this.updateEventsSource();
|
|
||||||
},
|
|
||||||
get() {
|
|
||||||
return this.showMyCalendar;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
computed: {
|
||||||
methods: {
|
showMyCalendarWidget: {
|
||||||
init() {
|
set(value) {
|
||||||
this.fetchData();
|
this.toggleMyCalendar(value);
|
||||||
|
this.updateEventsSource();
|
||||||
|
},
|
||||||
|
get() {
|
||||||
|
return this.showMyCalendar;
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
fetchData() {
|
methods: {
|
||||||
fetchCalendarRanges()
|
init() {
|
||||||
.then(
|
this.fetchData();
|
||||||
(calendarRanges) =>
|
},
|
||||||
new Promise((resolve, reject) => {
|
fetchData() {
|
||||||
let results = calendarRanges.results;
|
fetchCalendarRanges()
|
||||||
|
.then(
|
||||||
let users = [];
|
(calendarRanges) =>
|
||||||
|
|
||||||
results.forEach((i) => {
|
|
||||||
if (!users.some((j) => i.user.id === j.id)) {
|
|
||||||
let ratio = Math.floor(users.length / COLORS.length);
|
|
||||||
let colorIndex = users.length - ratio * COLORS.length;
|
|
||||||
users.push({
|
|
||||||
id: i.user.id,
|
|
||||||
username: i.user.username,
|
|
||||||
color: COLORS[colorIndex],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let calendarEvents = [];
|
|
||||||
users.forEach((u) => {
|
|
||||||
let arr = results
|
|
||||||
.filter((i) => i.user.id === u.id)
|
|
||||||
.map((i) => ({
|
|
||||||
start: i.startDate.datetime,
|
|
||||||
end: i.endDate.datetime,
|
|
||||||
calendarRangeId: i.id,
|
|
||||||
sourceColor: u.color,
|
|
||||||
//display: 'background' // can be an option for the disponibility
|
|
||||||
}));
|
|
||||||
calendarEvents.push({
|
|
||||||
events: arr,
|
|
||||||
color: u.color,
|
|
||||||
textColor: "#444444",
|
|
||||||
editable: false,
|
|
||||||
id: u.id,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.users.loaded = users;
|
|
||||||
this.options = users;
|
|
||||||
|
|
||||||
this.calendarEvents.loaded = calendarEvents;
|
|
||||||
whoami().then(
|
|
||||||
(me) =>
|
|
||||||
new Promise((resolve, reject) => {
|
|
||||||
this.users.logged = me;
|
|
||||||
let currentUser = users.find((u) => u.id === me.id);
|
|
||||||
this.value = currentUser;
|
|
||||||
|
|
||||||
fetchCalendar(currentUser.id).then(
|
|
||||||
(calendar) =>
|
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
let results = calendar.results;
|
let results = calendarRanges.results;
|
||||||
let events = results.map((i) => ({
|
|
||||||
start: i.startDate.datetime,
|
|
||||||
end: i.endDate.datetime,
|
|
||||||
}));
|
|
||||||
let calendarEventsCurrentUser = {
|
|
||||||
events: events,
|
|
||||||
color: "darkblue",
|
|
||||||
id: 1000,
|
|
||||||
editable: false,
|
|
||||||
};
|
|
||||||
this.calendarEvents.user = calendarEventsCurrentUser;
|
|
||||||
|
|
||||||
this.selectUsers(currentUser);
|
let users = [];
|
||||||
|
|
||||||
resolve();
|
results.forEach((i) => {
|
||||||
|
if (!users.some((j) => i.user.id === j.id)) {
|
||||||
|
let ratio = Math.floor(
|
||||||
|
users.length / COLORS.length,
|
||||||
|
);
|
||||||
|
let colorIndex =
|
||||||
|
users.length - ratio * COLORS.length;
|
||||||
|
users.push({
|
||||||
|
id: i.user.id,
|
||||||
|
username: i.user.username,
|
||||||
|
color: COLORS[colorIndex],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let calendarEvents = [];
|
||||||
|
users.forEach((u) => {
|
||||||
|
let arr = results
|
||||||
|
.filter((i) => i.user.id === u.id)
|
||||||
|
.map((i) => ({
|
||||||
|
start: i.startDate.datetime,
|
||||||
|
end: i.endDate.datetime,
|
||||||
|
calendarRangeId: i.id,
|
||||||
|
sourceColor: u.color,
|
||||||
|
//display: 'background' // can be an option for the disponibility
|
||||||
|
}));
|
||||||
|
calendarEvents.push({
|
||||||
|
events: arr,
|
||||||
|
color: u.color,
|
||||||
|
textColor: "#444444",
|
||||||
|
editable: false,
|
||||||
|
id: u.id,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.users.loaded = users;
|
||||||
|
this.options = users;
|
||||||
|
|
||||||
|
this.calendarEvents.loaded = calendarEvents;
|
||||||
|
whoami().then(
|
||||||
|
(me) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
this.users.logged = me;
|
||||||
|
let currentUser = users.find(
|
||||||
|
(u) => u.id === me.id,
|
||||||
|
);
|
||||||
|
this.value = currentUser;
|
||||||
|
|
||||||
|
fetchCalendar(currentUser.id).then(
|
||||||
|
(calendar) =>
|
||||||
|
new Promise(
|
||||||
|
(resolve, reject) => {
|
||||||
|
let results =
|
||||||
|
calendar.results;
|
||||||
|
let events =
|
||||||
|
results.map(
|
||||||
|
(i) => ({
|
||||||
|
start: i
|
||||||
|
.startDate
|
||||||
|
.datetime,
|
||||||
|
end: i
|
||||||
|
.endDate
|
||||||
|
.datetime,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
let calendarEventsCurrentUser =
|
||||||
|
{
|
||||||
|
events: events,
|
||||||
|
color: "darkblue",
|
||||||
|
id: 1000,
|
||||||
|
editable: false,
|
||||||
|
};
|
||||||
|
this.calendarEvents.user =
|
||||||
|
calendarEventsCurrentUser;
|
||||||
|
|
||||||
|
this.selectUsers(
|
||||||
|
currentUser,
|
||||||
|
);
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
resolve();
|
||||||
}),
|
}),
|
||||||
);
|
)
|
||||||
|
.catch((error) => {
|
||||||
|
this.errorMsg.push(error.message);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
transName(value) {
|
||||||
|
return `${value.username}`;
|
||||||
|
},
|
||||||
|
coloriseSelectedValues() {
|
||||||
|
let tags = document.querySelectorAll(
|
||||||
|
"div.multiselect__tags-wrap",
|
||||||
|
)[0];
|
||||||
|
|
||||||
resolve();
|
if (tags.hasChildNodes()) {
|
||||||
}),
|
let children = tags.childNodes;
|
||||||
);
|
for (let i = 0; i < children.length; i++) {
|
||||||
|
let child = children[i];
|
||||||
resolve();
|
if (child.nodeType === Node.ELEMENT_NODE) {
|
||||||
}),
|
this.users.selected.forEach((u) => {
|
||||||
)
|
if (child.hasChildNodes()) {
|
||||||
.catch((error) => {
|
if (child.firstChild.innerText == u.username) {
|
||||||
this.errorMsg.push(error.message);
|
child.style.background = u.color;
|
||||||
});
|
child.firstChild.style.color = "#444444";
|
||||||
},
|
}
|
||||||
transName(value) {
|
}
|
||||||
return `${value.username}`;
|
});
|
||||||
},
|
}
|
||||||
coloriseSelectedValues() {
|
|
||||||
let tags = document.querySelectorAll("div.multiselect__tags-wrap")[0];
|
|
||||||
|
|
||||||
if (tags.hasChildNodes()) {
|
|
||||||
let children = tags.childNodes;
|
|
||||||
for (let i = 0; i < children.length; i++) {
|
|
||||||
let child = children[i];
|
|
||||||
if (child.nodeType === Node.ELEMENT_NODE) {
|
|
||||||
this.users.selected.forEach((u) => {
|
|
||||||
if (child.hasChildNodes()) {
|
|
||||||
if (child.firstChild.innerText == u.username) {
|
|
||||||
child.style.background = u.color;
|
|
||||||
child.firstChild.style.color = "#444444";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
}
|
selectEvents() {
|
||||||
}
|
let selectedUsersId = this.users.selected.map((a) => a.id);
|
||||||
}
|
this.calendarEvents.selected = this.calendarEvents.loaded.filter(
|
||||||
|
(a) => selectedUsersId.includes(a.id),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
selectUsers(value) {
|
||||||
|
this.users.selected.push(value);
|
||||||
|
this.coloriseSelectedValues();
|
||||||
|
this.selectEvents();
|
||||||
|
this.updateEventsSource();
|
||||||
|
},
|
||||||
|
unSelectUsers(value) {
|
||||||
|
this.users.selected = this.users.selected.filter(
|
||||||
|
(a) => a.id != value.id,
|
||||||
|
);
|
||||||
|
this.selectEvents();
|
||||||
|
this.updateEventsSource();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
selectEvents() {
|
mounted() {
|
||||||
let selectedUsersId = this.users.selected.map((a) => a.id);
|
this.init();
|
||||||
this.calendarEvents.selected = this.calendarEvents.loaded.filter((a) =>
|
|
||||||
selectedUsersId.includes(a.id),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
selectUsers(value) {
|
|
||||||
this.users.selected.push(value);
|
|
||||||
this.coloriseSelectedValues();
|
|
||||||
this.selectEvents();
|
|
||||||
this.updateEventsSource();
|
|
||||||
},
|
|
||||||
unSelectUsers(value) {
|
|
||||||
this.users.selected = this.users.selected.filter((a) => a.id != value.id);
|
|
||||||
this.selectEvents();
|
|
||||||
this.updateEventsSource();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.init();
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style src="vue-multiselect/dist/vue-multiselect.css"></style>
|
|
||||||
|
|||||||
@@ -28,9 +28,6 @@
|
|||||||
{% if calendar.status == 'canceled' %}
|
{% if calendar.status == 'canceled' %}
|
||||||
<del>
|
<del>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if calendar.status == 'canceled' %}
|
|
||||||
<del>
|
|
||||||
{% endif %}
|
|
||||||
{% if calendar.endDate.diff(calendar.startDate).days >= 1 %}
|
{% if calendar.endDate.diff(calendar.startDate).days >= 1 %}
|
||||||
{{ calendar.startDate|format_datetime('short', 'short') }}
|
{{ calendar.startDate|format_datetime('short', 'short') }}
|
||||||
- {{ calendar.endDate|format_datetime('short', 'short') }}
|
- {{ calendar.endDate|format_datetime('short', 'short') }}
|
||||||
@@ -240,10 +237,6 @@
|
|||||||
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_cancel', { 'id': calendar.id } ) }}"
|
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_cancel', { 'id': calendar.id } ) }}"
|
||||||
class="btn btn-action"><i class="bi bi-x-circle"></i> {{ 'Cancel'|trans }}</a>
|
class="btn btn-action"><i class="bi bi-x-circle"></i> {{ 'Cancel'|trans }}</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_cancel', { 'id': calendar.id } ) }}"
|
|
||||||
class="btn btn-action"><i class="bi bi-x-circle"></i> {{ 'Cancel'|trans }}</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if is_granted('CHILL_CALENDAR_CALENDAR_DELETE', calendar) %}
|
{% if is_granted('CHILL_CALENDAR_CALENDAR_DELETE', calendar) %}
|
||||||
|
|||||||
@@ -20,13 +20,13 @@
|
|||||||
window.endDate = {{ entity.endDate|date('Y-m-d H:i:s')|json_encode|raw }};
|
window.endDate = {{ entity.endDate|date('Y-m-d H:i:s')|json_encode|raw }};
|
||||||
window.mainUser = {{ entity.mainUser.id }};
|
window.mainUser = {{ entity.mainUser.id }};
|
||||||
</script>
|
</script>
|
||||||
{{ encore_entry_script_tags('vue_calendar') }}
|
{{ vite_entry_script_tags('vue_calendar') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('vue_calendar') }}
|
{{ vite_entry_link_tags('vue_calendar') }}
|
||||||
{{ encore_entry_link_tags('page_calendar') }}
|
{{ vite_entry_link_tags('page_calendar') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block block_post_menu %}
|
{% block block_post_menu %}
|
||||||
|
|||||||
@@ -20,13 +20,13 @@
|
|||||||
window.endDate = {{ entity.endDate|date('Y-m-d H:i:s')|json_encode|raw }};
|
window.endDate = {{ entity.endDate|date('Y-m-d H:i:s')|json_encode|raw }};
|
||||||
window.mainUser = {{ entity.mainUser.id }};
|
window.mainUser = {{ entity.mainUser.id }};
|
||||||
</script>
|
</script>
|
||||||
{{ encore_entry_script_tags('vue_calendar') }}
|
{{ vite_entry_script_tags('vue_calendar') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('vue_calendar') }}
|
{{ vite_entry_link_tags('vue_calendar') }}
|
||||||
{{ encore_entry_link_tags('page_calendar') }}
|
{{ vite_entry_link_tags('page_calendar') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block block_post_menu %}
|
{% block block_post_menu %}
|
||||||
|
|||||||
@@ -23,10 +23,10 @@
|
|||||||
window.endDate = {{ entity.endDate|date('Y-m-d H:i:s')|json_encode|raw }};
|
window.endDate = {{ entity.endDate|date('Y-m-d H:i:s')|json_encode|raw }};
|
||||||
window.mainUser = {{ entity.mainUser.id }};
|
window.mainUser = {{ entity.mainUser.id }};
|
||||||
</script>
|
</script>
|
||||||
{{ encore_entry_script_tags('vue_calendar') }}
|
{{ vite_entry_script_tags('vue_calendar') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('vue_calendar') }}
|
{{ vite_entry_link_tags('vue_calendar') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -9,14 +9,14 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_answer') }}
|
{{ vite_entry_script_tags('mod_answer') }}
|
||||||
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
|
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('mod_answer') }}
|
{{ vite_entry_link_tags('mod_answer') }}
|
||||||
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
|
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -8,14 +8,14 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_answer') }}
|
{{ vite_entry_script_tags('mod_answer') }}
|
||||||
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
|
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('mod_answer') }}
|
{{ vite_entry_link_tags('mod_answer') }}
|
||||||
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
|
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.userId = {{ user.id }};
|
window.userId = {{ user.id }};
|
||||||
</script>
|
</script>
|
||||||
{{ encore_entry_script_tags('vue_mycalendarrange') }}
|
{{ vite_entry_script_tags('vue_mycalendarrange') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('vue_mycalendarrange') }}
|
{{ vite_entry_link_tags('vue_mycalendarrange') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -15,18 +15,18 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_pickentity_type') }}
|
{{ vite_entry_script_tags('mod_pickentity_type') }}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.entity = {{ entity_json|json_encode|raw }};
|
window.entity = {{ entity_json|json_encode|raw }};
|
||||||
{% if app.user.currentLocation is not null %}window.default_location_id = {{ app.user.currentLocation.id }};{% endif %};
|
{% if app.user.currentLocation is not null %}window.default_location_id = {{ app.user.currentLocation.id }};{% endif %};
|
||||||
</script>
|
</script>
|
||||||
{{ encore_entry_script_tags('vue_calendar') }}
|
{{ vite_entry_script_tags('vue_calendar') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('vue_calendar') }}
|
{{ vite_entry_link_tags('vue_calendar') }}
|
||||||
{{ encore_entry_link_tags('mod_pickentity_type') }}
|
{{ vite_entry_link_tags('mod_pickentity_type') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block block_post_menu %}
|
{% block block_post_menu %}
|
||||||
|
|||||||
@@ -15,18 +15,18 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_pickentity_type') }}
|
{{ vite_entry_script_tags('mod_pickentity_type') }}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.entity = {{ entity_json|json_encode|raw }};
|
window.entity = {{ entity_json|json_encode|raw }};
|
||||||
{% if app.user.currentLocation is not null %}window.default_location_id = {{ app.user.currentLocation.id }};{% endif %};
|
{% if app.user.currentLocation is not null %}window.default_location_id = {{ app.user.currentLocation.id }};{% endif %};
|
||||||
</script>
|
</script>
|
||||||
{{ encore_entry_script_tags('vue_calendar') }}
|
{{ vite_entry_script_tags('vue_calendar') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('vue_calendar') }}
|
{{ vite_entry_link_tags('vue_calendar') }}
|
||||||
{{ encore_entry_link_tags('mod_pickentity_type') }}
|
{{ vite_entry_link_tags('mod_pickentity_type') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block block_post_menu %}
|
{% block block_post_menu %}
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_async_upload') }}
|
{{ vite_entry_script_tags('mod_async_upload') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('mod_async_upload') }}
|
{{ vite_entry_link_tags('mod_async_upload') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -8,12 +8,12 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_async_upload') }}
|
{{ vite_entry_script_tags('mod_async_upload') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('mod_async_upload') }}
|
{{ vite_entry_link_tags('mod_async_upload') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_async_upload') }}
|
{{ vite_entry_script_tags('mod_async_upload') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('mod_async_upload') }}
|
{{ vite_entry_link_tags('mod_async_upload') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -8,12 +8,12 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_async_upload') }}
|
{{ vite_entry_script_tags('mod_async_upload') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('mod_async_upload') }}
|
{{ vite_entry_link_tags('mod_async_upload') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@@ -29,12 +29,12 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_script_tags('mod_answer') }}
|
{{ vite_entry_script_tags('mod_answer') }}
|
||||||
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
|
{{ vite_entry_script_tags('mod_document_action_buttons_group') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ parent() }}
|
{{ parent() }}
|
||||||
{{ encore_entry_link_tags('mod_answer') }}
|
{{ vite_entry_link_tags('mod_answer') }}
|
||||||
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
|
{{ vite_entry_link_tags('mod_document_action_buttons_group') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
// this file loads all assets from the Chill calendar bundle
|
|
||||||
module.exports = function (encore, entries) {
|
|
||||||
entries.push(__dirname + "/Resources/public/chill/chill.js");
|
|
||||||
|
|
||||||
encore.addAliases({
|
|
||||||
ChillCalendarAssets: __dirname + "/Resources/public",
|
|
||||||
});
|
|
||||||
|
|
||||||
encore.addEntry(
|
|
||||||
"vue_calendar",
|
|
||||||
__dirname + "/Resources/public/vuejs/Calendar/index.js",
|
|
||||||
);
|
|
||||||
encore.addEntry(
|
|
||||||
"vue_mycalendarrange",
|
|
||||||
__dirname + "/Resources/public/vuejs/MyCalendarRange/index2.ts",
|
|
||||||
);
|
|
||||||
encore.addEntry(
|
|
||||||
"page_calendar",
|
|
||||||
__dirname + "/Resources/public/chill/index.js",
|
|
||||||
);
|
|
||||||
encore.addEntry(
|
|
||||||
"mod_answer",
|
|
||||||
__dirname + "/Resources/public/module/Invite/answer.js",
|
|
||||||
);
|
|
||||||
};
|
|
||||||
18
src/Bundle/ChillCalendarBundle/vite.config.js
Normal file
18
src/Bundle/ChillCalendarBundle/vite.config.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
export default {
|
||||||
|
chillBase: [
|
||||||
|
"./src/Bundle/ChillCalendarBundle/Resources/public/chill/chill.js",
|
||||||
|
],
|
||||||
|
aliases: {
|
||||||
|
ChillCalendarAssets: "./src/Bundle/ChillCalendarBundle/Resources/public",
|
||||||
|
},
|
||||||
|
inputs: {
|
||||||
|
vue_calendar:
|
||||||
|
"./src/Bundle/ChillCalendarBundle/Resources/public/vuejs/Calendar/index.js",
|
||||||
|
vue_mycalendarrange:
|
||||||
|
"./src/Bundle/ChillCalendarBundle/Resources/public/vuejs/MyCalendarRange/index2.ts",
|
||||||
|
page_calendar:
|
||||||
|
"./src/Bundle/ChillCalendarBundle/Resources/public/chill/index.js",
|
||||||
|
mod_answer:
|
||||||
|
"./src/Bundle/ChillCalendarBundle/Resources/public/module/Invite/answer.js",
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1,54 +1,59 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<template v-if="templates.length > 0">
|
<template v-if="templates.length > 0">
|
||||||
<slot name="title">
|
<slot name="title">
|
||||||
<h2>{{ $t("generate_document") }}</h2>
|
<h2>{{ $t("generate_document") }}</h2>
|
||||||
</slot>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<slot name="label">
|
|
||||||
<label>{{ $t("select_a_template") }}</label>
|
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
|
||||||
<div class="col-md-8">
|
<div class="container">
|
||||||
<div class="input-group mb-3">
|
<div class="row">
|
||||||
<select class="form-select" v-model="template">
|
<div class="col-md-4">
|
||||||
<option disabled selected value="">
|
<slot name="label">
|
||||||
{{ $t("choose_a_template") }}
|
<label>{{ $t("select_a_template") }}</label>
|
||||||
</option>
|
</slot>
|
||||||
<template v-for="t in templates" :key="t.id">
|
</div>
|
||||||
<option :value="t.id">
|
<div class="col-md-8">
|
||||||
{{ localizeString(t.name) || "Aucun nom défini" }}
|
<div class="input-group mb-3">
|
||||||
</option>
|
<select class="form-select" v-model="template">
|
||||||
</template>
|
<option disabled selected value="">
|
||||||
</select>
|
{{ $t("choose_a_template") }}
|
||||||
<a
|
</option>
|
||||||
v-if="canGenerate"
|
<template v-for="t in templates" :key="t.id">
|
||||||
class="btn btn-update btn-sm change-icon"
|
<option :value="t.id">
|
||||||
:href="buildUrlGenerate"
|
{{
|
||||||
@click.prevent="clickGenerate($event, buildUrlGenerate)"
|
localizeString(t.name) ||
|
||||||
><i class="fa fa-fw fa-cog"
|
"Aucun nom défini"
|
||||||
/></a>
|
}}
|
||||||
<a
|
</option>
|
||||||
v-else
|
</template>
|
||||||
class="btn btn-update btn-sm change-icon"
|
</select>
|
||||||
href="#"
|
<a
|
||||||
disabled
|
v-if="canGenerate"
|
||||||
><i class="fa fa-fw fa-cog"
|
class="btn btn-update btn-sm change-icon"
|
||||||
/></a>
|
:href="buildUrlGenerate"
|
||||||
|
@click.prevent="
|
||||||
|
clickGenerate($event, buildUrlGenerate)
|
||||||
|
"
|
||||||
|
><i class="fa fa-fw fa-cog"
|
||||||
|
/></a>
|
||||||
|
<a
|
||||||
|
v-else
|
||||||
|
class="btn btn-update btn-sm change-icon"
|
||||||
|
href="#"
|
||||||
|
disabled
|
||||||
|
><i class="fa fa-fw fa-cog"
|
||||||
|
/></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row" v-if="hasDescription">
|
||||||
|
<div class="col-md-8 align-self-end">
|
||||||
|
<p>{{ getDescription }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" v-if="hasDescription">
|
|
||||||
<div class="col-md-8 align-self-end">
|
|
||||||
<p>{{ getDescription }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -56,83 +61,83 @@ import { buildLink } from "ChillDocGeneratorAssets/lib/document-generator";
|
|||||||
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
import { localizeString } from "ChillMainAssets/lib/localizationHelper/localizationHelper";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PickTemplate",
|
name: "PickTemplate",
|
||||||
props: {
|
props: {
|
||||||
entityId: [String, Number],
|
entityId: [String, Number],
|
||||||
entityClass: {
|
entityClass: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
|
},
|
||||||
|
templates: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
preventDefaultMoveToGenerate: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
templates: {
|
emits: ["goToGenerateDocument"],
|
||||||
type: Array,
|
data() {
|
||||||
required: true,
|
return {
|
||||||
|
template: null,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
preventDefaultMoveToGenerate: {
|
computed: {
|
||||||
type: Boolean,
|
canGenerate() {
|
||||||
required: false,
|
return this.template != null;
|
||||||
default: false,
|
},
|
||||||
},
|
hasDescription() {
|
||||||
},
|
if (this.template == null) {
|
||||||
emits: ["goToGenerateDocument"],
|
return false;
|
||||||
data() {
|
}
|
||||||
return {
|
|
||||||
template: null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
canGenerate() {
|
|
||||||
return this.template != null;
|
|
||||||
},
|
|
||||||
hasDescription() {
|
|
||||||
if (this.template == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
getDescription() {
|
getDescription() {
|
||||||
if (null === this.template) {
|
if (null === this.template) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
let desc = this.templates.find((t) => t.id === this.template);
|
let desc = this.templates.find((t) => t.id === this.template);
|
||||||
if (null === desc) {
|
if (null === desc) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return desc.description || "";
|
return desc.description || "";
|
||||||
},
|
},
|
||||||
buildUrlGenerate() {
|
buildUrlGenerate() {
|
||||||
if (null === this.template) {
|
if (null === this.template) {
|
||||||
return "#";
|
return "#";
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildLink(this.template, this.entityId, this.entityClass);
|
return buildLink(this.template, this.entityId, this.entityClass);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
methods: {
|
||||||
methods: {
|
localizeString(str) {
|
||||||
localizeString(str) {
|
return localizeString(str);
|
||||||
return localizeString(str);
|
},
|
||||||
},
|
clickGenerate(event, link) {
|
||||||
clickGenerate(event, link) {
|
if (!this.preventDefaultMoveToGenerate) {
|
||||||
if (!this.preventDefaultMoveToGenerate) {
|
window.location.assign(link);
|
||||||
window.location.assign(link);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
this.$emit("goToGenerateDocument", {
|
this.$emit("goToGenerateDocument", {
|
||||||
event,
|
event,
|
||||||
link,
|
link,
|
||||||
template: this.template,
|
template: this.template,
|
||||||
});
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
i18n: {
|
||||||
i18n: {
|
messages: {
|
||||||
messages: {
|
fr: {
|
||||||
fr: {
|
generate_document: "Générer un document",
|
||||||
generate_document: "Générer un document",
|
select_a_template: "Choisir un modèle",
|
||||||
select_a_template: "Choisir un modèle",
|
choose_a_template: "Choisir",
|
||||||
choose_a_template: "Choisir",
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</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