mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
add scope selection on accompanying course
This commit is contained in:
parent
c382008b4d
commit
c62254caec
@ -3,17 +3,17 @@
|
|||||||
/*
|
/*
|
||||||
* Chill is a suite of a modules, Chill is a software for social workers
|
* Chill is a suite of a modules, Chill is a software for social workers
|
||||||
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* it under the terms of the GNU Affero General Public License as
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
* License, or (at your option) any later version.
|
* License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Affero General Public License for more details.
|
* GNU Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
@ -46,17 +46,17 @@ class Scope
|
|||||||
* @Groups({"read"})
|
* @Groups({"read"})
|
||||||
*/
|
*/
|
||||||
private $id;
|
private $id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* translatable names
|
* translatable names
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*
|
*
|
||||||
* @ORM\Column(type="json_array")
|
* @ORM\Column(type="json_array")
|
||||||
* @Groups({"read"})
|
* @Groups({"read"})
|
||||||
*/
|
*/
|
||||||
private $name = [];
|
private $name = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Collection
|
* @var Collection
|
||||||
*
|
*
|
||||||
@ -66,8 +66,8 @@ class Scope
|
|||||||
* @ORM\Cache(usage="NONSTRICT_READ_WRITE")
|
* @ORM\Cache(usage="NONSTRICT_READ_WRITE")
|
||||||
*/
|
*/
|
||||||
private $roleScopes;
|
private $roleScopes;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scope constructor.
|
* Scope constructor.
|
||||||
*/
|
*/
|
||||||
@ -75,7 +75,7 @@ class Scope
|
|||||||
{
|
{
|
||||||
$this->roleScopes = new ArrayCollection();
|
$this->roleScopes = new ArrayCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
@ -91,7 +91,7 @@ class Scope
|
|||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $name
|
* @param $name
|
||||||
* @return $this
|
* @return $this
|
||||||
@ -101,7 +101,7 @@ class Scope
|
|||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Collection
|
* @return Collection
|
||||||
*/
|
*/
|
||||||
@ -109,7 +109,7 @@ class Scope
|
|||||||
{
|
{
|
||||||
return $this->roleScopes;
|
return $this->roleScopes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param RoleScope $roleScope
|
* @param RoleScope $roleScope
|
||||||
*/
|
*/
|
||||||
|
17
src/Bundle/ChillMainBundle/Resources/public/lib/api/scope.js
Normal file
17
src/Bundle/ChillMainBundle/Resources/public/lib/api/scope.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const fetchScopes = () => {
|
||||||
|
return window.fetch('/api/1.0/main/scope.json').then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
}).then(data => {
|
||||||
|
console.log(data);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log(data);
|
||||||
|
resolve(data.results);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
fetchScopes
|
||||||
|
};
|
@ -2,16 +2,21 @@
|
|||||||
|
|
||||||
namespace Chill\MainBundle\Security\Resolver;
|
namespace Chill\MainBundle\Security\Resolver;
|
||||||
|
|
||||||
use Chill\MainBundle\Entity\Center;
|
|
||||||
use Chill\MainBundle\Entity\Scope;
|
use Chill\MainBundle\Entity\Scope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to implement to define a ScopeResolver.
|
||||||
|
*/
|
||||||
interface ScopeResolverInterface
|
interface ScopeResolverInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Return true if this resolve is able to decide "something" on this entity.
|
||||||
|
*/
|
||||||
public function supports($entity, ?array $options = []): bool;
|
public function supports($entity, ?array $options = []): bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $entity
|
* Will return the scope for the entity
|
||||||
* @param array|null $options
|
*
|
||||||
* @return Scope|array|Scope[]
|
* @return Scope|array|Scope[]
|
||||||
*/
|
*/
|
||||||
public function resolveScope($entity, ?array $options = []);
|
public function resolveScope($entity, ?array $options = []);
|
||||||
@ -19,12 +24,12 @@ interface ScopeResolverInterface
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if the entity is concerned by scope, false otherwise.
|
* Return true if the entity is concerned by scope, false otherwise.
|
||||||
*
|
|
||||||
* @param $entity
|
|
||||||
* @param array|null $options
|
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
public function isConcerned($entity, ?array $options = []): bool;
|
public function isConcerned($entity, ?array $options = []): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the default priority for this resolver. Resolver with an higher priority will be
|
||||||
|
* queried first.
|
||||||
|
*/
|
||||||
public static function getDefaultPriority(): int;
|
public static function getDefaultPriority(): int;
|
||||||
}
|
}
|
||||||
|
@ -491,3 +491,23 @@ paths:
|
|||||||
description: "ok"
|
description: "ok"
|
||||||
401:
|
401:
|
||||||
description: "Unauthorized"
|
description: "Unauthorized"
|
||||||
|
|
||||||
|
/1.0/main/scope/{id}.json:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- scope
|
||||||
|
summary: return a list of scopes
|
||||||
|
parameters:
|
||||||
|
- name: id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
description: The scope id
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: integer
|
||||||
|
minimum: 1
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "ok"
|
||||||
|
401:
|
||||||
|
description: "Unauthorized"
|
||||||
|
@ -24,8 +24,12 @@ namespace Chill\PersonBundle\DataFixtures\ORM;
|
|||||||
use Chill\MainBundle\Entity\Center;
|
use Chill\MainBundle\Entity\Center;
|
||||||
use Chill\MainBundle\Entity\Country;
|
use Chill\MainBundle\Entity\Country;
|
||||||
use Chill\MainBundle\Entity\PostalCode;
|
use Chill\MainBundle\Entity\PostalCode;
|
||||||
|
use Chill\MainBundle\Entity\Scope;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
use Chill\MainBundle\Repository\CenterRepository;
|
use Chill\MainBundle\Repository\CenterRepository;
|
||||||
use Chill\MainBundle\Repository\CountryRepository;
|
use Chill\MainBundle\Repository\CountryRepository;
|
||||||
|
use Chill\MainBundle\Repository\ScopeRepository;
|
||||||
|
use Chill\MainBundle\Repository\UserRepository;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Entity\MaritalStatus;
|
use Chill\PersonBundle\Entity\MaritalStatus;
|
||||||
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
|
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
|
||||||
@ -90,12 +94,26 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
|||||||
|
|
||||||
protected MaritalStatusRepository $maritalStatusRepository;
|
protected MaritalStatusRepository $maritalStatusRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array|Scope[]
|
||||||
|
*/
|
||||||
|
protected array $cacheScopes = [];
|
||||||
|
|
||||||
|
protected ScopeRepository $scopeRepository;
|
||||||
|
|
||||||
|
/** @var array|User[] */
|
||||||
|
protected array $cacheUsers = [];
|
||||||
|
|
||||||
|
protected UserRepository $userRepository;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
Registry $workflowRegistry,
|
Registry $workflowRegistry,
|
||||||
SocialIssueRepository $socialIssueRepository,
|
SocialIssueRepository $socialIssueRepository,
|
||||||
CenterRepository $centerRepository,
|
CenterRepository $centerRepository,
|
||||||
CountryRepository $countryRepository,
|
CountryRepository $countryRepository,
|
||||||
MaritalStatusRepository $maritalStatusRepository
|
MaritalStatusRepository $maritalStatusRepository,
|
||||||
|
ScopeRepository $scopeRepository,
|
||||||
|
UserRepository $userRepository
|
||||||
) {
|
) {
|
||||||
$this->faker = Factory::create('fr_FR');
|
$this->faker = Factory::create('fr_FR');
|
||||||
$this->faker->addProvider($this);
|
$this->faker->addProvider($this);
|
||||||
@ -105,7 +123,8 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
|||||||
$this->countryRepository = $countryRepository;
|
$this->countryRepository = $countryRepository;
|
||||||
$this->maritalStatusRepository = $maritalStatusRepository;
|
$this->maritalStatusRepository = $maritalStatusRepository;
|
||||||
$this->loader = new NativeLoader($this->faker);
|
$this->loader = new NativeLoader($this->faker);
|
||||||
|
$this->scopeRepository = $scopeRepository;
|
||||||
|
$this->userRepository = $userRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOrder()
|
public function getOrder()
|
||||||
@ -220,10 +239,16 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
|||||||
new \DateInterval('P' . \random_int(0, 180) . 'D')
|
new \DateInterval('P' . \random_int(0, 180) . 'D')
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
$accompanyingPeriod->setCreatedBy($this->getRandomUser())
|
||||||
|
->setCreatedAt(new \DateTimeImmutable('now'));
|
||||||
$person->addAccompanyingPeriod($accompanyingPeriod);
|
$person->addAccompanyingPeriod($accompanyingPeriod);
|
||||||
$accompanyingPeriod->addSocialIssue($this->getRandomSocialIssue());
|
$accompanyingPeriod->addSocialIssue($this->getRandomSocialIssue());
|
||||||
|
|
||||||
if (\random_int(0, 10) > 3) {
|
if (\random_int(0, 10) > 3) {
|
||||||
|
// always add social scope:
|
||||||
|
$accompanyingPeriod->addScope($this->getReference('scope_social'));
|
||||||
|
var_dump(count($accompanyingPeriod->getScopes()));
|
||||||
|
|
||||||
$accompanyingPeriod->setAddressLocation($this->createAddress());
|
$accompanyingPeriod->setAddressLocation($this->createAddress());
|
||||||
$manager->persist($accompanyingPeriod->getAddressLocation());
|
$manager->persist($accompanyingPeriod->getAddressLocation());
|
||||||
$workflow = $this->workflowRegistry->get($accompanyingPeriod);
|
$workflow = $this->workflowRegistry->get($accompanyingPeriod);
|
||||||
@ -231,9 +256,19 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
|||||||
}
|
}
|
||||||
|
|
||||||
$manager->persist($person);
|
$manager->persist($person);
|
||||||
|
$manager->persist($accompanyingPeriod);
|
||||||
echo "add person'".$person->__toString()."'\n";
|
echo "add person'".$person->__toString()."'\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getRandomUser(): User
|
||||||
|
{
|
||||||
|
if (0 === count($this->cacheUsers)) {
|
||||||
|
$this->cacheUsers = $this->userRepository->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->cacheUsers[\array_rand($this->cacheUsers)];
|
||||||
|
}
|
||||||
|
|
||||||
private function createAddress(): Address
|
private function createAddress(): Address
|
||||||
{
|
{
|
||||||
$objectSet = $this->loader->loadData([
|
$objectSet = $this->loader->loadData([
|
||||||
|
@ -40,13 +40,13 @@ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface
|
|||||||
return 9600;
|
return 9600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function load(ObjectManager $manager)
|
public function load(ObjectManager $manager)
|
||||||
{
|
{
|
||||||
foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) {
|
foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) {
|
||||||
$permissionsGroup = $this->getReference($permissionsGroupRef);
|
$permissionsGroup = $this->getReference($permissionsGroupRef);
|
||||||
$scopeSocial = $this->getReference('scope_social');
|
$scopeSocial = $this->getReference('scope_social');
|
||||||
|
|
||||||
//create permission group
|
//create permission group
|
||||||
switch ($permissionsGroup->getName()) {
|
switch ($permissionsGroup->getName()) {
|
||||||
case 'social':
|
case 'social':
|
||||||
@ -55,7 +55,7 @@ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface
|
|||||||
|
|
||||||
$permissionsGroup->addRoleScope(
|
$permissionsGroup->addRoleScope(
|
||||||
(new RoleScope())
|
(new RoleScope())
|
||||||
->setRole(AccompanyingPeriodVoter::SEE)
|
->setRole(AccompanyingPeriodVoter::FULL)
|
||||||
->setScope($scopeSocial)
|
->setScope($scopeSocial)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface
|
|||||||
$manager->persist($roleScopeUpdate);
|
$manager->persist($roleScopeUpdate);
|
||||||
$manager->persist($roleScopeCreate);
|
$manager->persist($roleScopeCreate);
|
||||||
$manager->persist($roleScopeDuplicate);
|
$manager->persist($roleScopeDuplicate);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'administrative':
|
case 'administrative':
|
||||||
printf("Adding CHILL_PERSON_SEE to %s permission group \n", $permissionsGroup->getName());
|
printf("Adding CHILL_PERSON_SEE to %s permission group \n", $permissionsGroup->getName());
|
||||||
@ -98,9 +98,9 @@ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface
|
|||||||
$manager->persist($roleScopeSee);
|
$manager->persist($roleScopeSee);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$manager->flush();
|
$manager->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -824,7 +824,9 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
|
|
||||||
public function addScope(Scope $scope): self
|
public function addScope(Scope $scope): self
|
||||||
{
|
{
|
||||||
$this->scopes[] = $scope;
|
if (!$this->scopes->contains($scope)) {
|
||||||
|
$this->scopes[] = $scope;
|
||||||
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
<origin-demand></origin-demand>
|
<origin-demand></origin-demand>
|
||||||
<requestor></requestor>
|
<requestor></requestor>
|
||||||
<social-issue></social-issue>
|
<social-issue></social-issue>
|
||||||
|
<scopes></scopes>
|
||||||
<referrer></referrer>
|
<referrer></referrer>
|
||||||
<resources></resources>
|
<resources></resources>
|
||||||
<comment v-if="accompanyingCourse.step === 'DRAFT'"></comment>
|
<comment v-if="accompanyingCourse.step === 'DRAFT'"></comment>
|
||||||
@ -32,6 +33,7 @@ import PersonsAssociated from './components/PersonsAssociated.vue';
|
|||||||
import Requestor from './components/Requestor.vue';
|
import Requestor from './components/Requestor.vue';
|
||||||
import SocialIssue from './components/SocialIssue.vue';
|
import SocialIssue from './components/SocialIssue.vue';
|
||||||
import CourseLocation from './components/CourseLocation.vue';
|
import CourseLocation from './components/CourseLocation.vue';
|
||||||
|
import Scopes from './components/Scopes.vue';
|
||||||
import Referrer from './components/Referrer.vue';
|
import Referrer from './components/Referrer.vue';
|
||||||
import Resources from './components/Resources.vue';
|
import Resources from './components/Resources.vue';
|
||||||
import Comment from './components/Comment.vue';
|
import Comment from './components/Comment.vue';
|
||||||
@ -47,6 +49,7 @@ export default {
|
|||||||
Requestor,
|
Requestor,
|
||||||
SocialIssue,
|
SocialIssue,
|
||||||
CourseLocation,
|
CourseLocation,
|
||||||
|
Scopes,
|
||||||
Referrer,
|
Referrer,
|
||||||
Resources,
|
Resources,
|
||||||
Comment,
|
Comment,
|
||||||
|
@ -191,7 +191,49 @@ const getListOrigins = () => {
|
|||||||
if (response.ok) { return response.json(); }
|
if (response.ok) { return response.json(); }
|
||||||
throw { msg: 'Error while retriving origin\'s list.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
|
throw { msg: 'Error while retriving origin\'s list.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const addScope = (id, scope) => {
|
||||||
|
const url = `/api/1.0/person/accompanying-course/${id}/scope.json`;
|
||||||
|
console.log(url);
|
||||||
|
console.log(scope);
|
||||||
|
|
||||||
|
return fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
id: scope.id,
|
||||||
|
type: scope.type,
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json;charset=utf-8'
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) { return response.json(); }
|
||||||
|
throw { msg: 'Error while adding scope', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeScope = (id, scope) => {
|
||||||
|
const url = `/api/1.0/person/accompanying-course/${id}/scope.json`;
|
||||||
|
console.log(url);
|
||||||
|
console.log(scope);
|
||||||
|
|
||||||
|
return fetch(url, {
|
||||||
|
method: 'DELETE',
|
||||||
|
body: JSON.stringify({
|
||||||
|
id: scope.id,
|
||||||
|
type: scope.type,
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json;charset=utf-8'
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) { return response.json(); }
|
||||||
|
throw { msg: 'Error while adding scope', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getAccompanyingCourse,
|
getAccompanyingCourse,
|
||||||
@ -204,5 +246,7 @@ export {
|
|||||||
getUsers,
|
getUsers,
|
||||||
whoami,
|
whoami,
|
||||||
getListOrigins,
|
getListOrigins,
|
||||||
postSocialIssue
|
postSocialIssue,
|
||||||
|
addScope,
|
||||||
|
removeScope,
|
||||||
};
|
};
|
||||||
|
@ -88,6 +88,10 @@ export default {
|
|||||||
socialIssue: {
|
socialIssue: {
|
||||||
msg: 'confirm.socialIssue_not_valid',
|
msg: 'confirm.socialIssue_not_valid',
|
||||||
anchor: '#section-50'
|
anchor: '#section-50'
|
||||||
|
},
|
||||||
|
scopes: {
|
||||||
|
msg: 'confirm.set_a_scope',
|
||||||
|
anchor: '#section-65'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
<template>
|
||||||
|
<div class="vue-component">
|
||||||
|
<h2><a name="section-65"></a>{{ $t('scopes.title') }}</h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li v-for="s in scopes">
|
||||||
|
<input type="checkbox" v-model="checkedScopes" :value="s" />
|
||||||
|
{{ s.name.fr }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div v-if="!isScopeValid" class="alert alert-warning separator">
|
||||||
|
{{ $t('scopes.add_at_least_one') }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { mapState, mapGetters } from 'vuex';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Scopes",
|
||||||
|
computed: {
|
||||||
|
...mapState([
|
||||||
|
'scopes',
|
||||||
|
'scopesAtStart'
|
||||||
|
]),
|
||||||
|
...mapGetters([
|
||||||
|
'isScopeValid'
|
||||||
|
]),
|
||||||
|
checkedScopes: {
|
||||||
|
get: function() {
|
||||||
|
return this.$store.state.accompanyingCourse.scopes;
|
||||||
|
},
|
||||||
|
set: function(v) {
|
||||||
|
this.$store.dispatch('setScopes', v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -86,6 +86,10 @@ const appMessages = {
|
|||||||
person_locator: "Parcours localisé auprès de {0}",
|
person_locator: "Parcours localisé auprès de {0}",
|
||||||
no_address: "Il n'y a pas d'adresse associée au parcours"
|
no_address: "Il n'y a pas d'adresse associée au parcours"
|
||||||
},
|
},
|
||||||
|
scopes: {
|
||||||
|
title: "Services",
|
||||||
|
add_at_least_one: "Indiquez au moins un service",
|
||||||
|
},
|
||||||
referrer: {
|
referrer: {
|
||||||
title: "Référent du parcours",
|
title: "Référent du parcours",
|
||||||
label: "Vous pouvez choisir un TMS ou vous assigner directement comme référent",
|
label: "Vous pouvez choisir un TMS ou vous assigner directement comme référent",
|
||||||
@ -113,6 +117,7 @@ const appMessages = {
|
|||||||
participation_not_valid: "sélectionnez au minimum 1 usager",
|
participation_not_valid: "sélectionnez au minimum 1 usager",
|
||||||
socialIssue_not_valid: "sélectionnez au minimum une problématique sociale",
|
socialIssue_not_valid: "sélectionnez au minimum une problématique sociale",
|
||||||
location_not_valid: "indiquez au minimum une localisation temporaire du parcours",
|
location_not_valid: "indiquez au minimum une localisation temporaire du parcours",
|
||||||
|
set_a_scope: "indiquez au moins un service",
|
||||||
sure: "Êtes-vous sûr ?",
|
sure: "Êtes-vous sûr ?",
|
||||||
sure_description: "Une fois le changement confirmé, il ne sera plus possible de le remettre à l'état de brouillon !",
|
sure_description: "Une fois le changement confirmé, il ne sera plus possible de le remettre à l'état de brouillon !",
|
||||||
ok: "Confirmer le parcours"
|
ok: "Confirmer le parcours"
|
||||||
|
@ -1,28 +1,41 @@
|
|||||||
import 'es6-promise/auto';
|
import 'es6-promise/auto';
|
||||||
import { createStore } from 'vuex';
|
import { createStore } from 'vuex';
|
||||||
|
import { fetchScopes } from 'ChillMainAssets/lib/api/scope.js';
|
||||||
import { getAccompanyingCourse,
|
import { getAccompanyingCourse,
|
||||||
patchAccompanyingCourse,
|
patchAccompanyingCourse,
|
||||||
confirmAccompanyingCourse,
|
confirmAccompanyingCourse,
|
||||||
postParticipation,
|
postParticipation,
|
||||||
postRequestor,
|
postRequestor,
|
||||||
postResource,
|
postResource,
|
||||||
postSocialIssue } from '../api';
|
postSocialIssue,
|
||||||
|
addScope,
|
||||||
|
removeScope,
|
||||||
|
} from '../api';
|
||||||
|
|
||||||
|
|
||||||
const debug = process.env.NODE_ENV !== 'production';
|
const debug = process.env.NODE_ENV !== 'production';
|
||||||
const id = window.accompanyingCourseId;
|
const id = window.accompanyingCourseId;
|
||||||
|
|
||||||
let initPromise = getAccompanyingCourse(id)
|
let scopesPromise = fetchScopes();
|
||||||
.then(accompanying_course => new Promise((resolve, reject) => {
|
let accompanyingCoursePromise = getAccompanyingCourse(id);
|
||||||
|
|
||||||
|
let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
||||||
|
.then(([scopes, accompanyingCourse]) => new Promise((resolve, reject) => {
|
||||||
|
|
||||||
const store = createStore({
|
const store = createStore({
|
||||||
strict: debug,
|
strict: debug,
|
||||||
modules: {
|
modules: {
|
||||||
},
|
},
|
||||||
state: {
|
state: {
|
||||||
accompanyingCourse: accompanying_course,
|
accompanyingCourse: accompanyingCourse,
|
||||||
addressContext: {},
|
addressContext: {},
|
||||||
errorMsg: []
|
errorMsg: [],
|
||||||
|
// all the available scopes
|
||||||
|
scopes: scopes,
|
||||||
|
// the scopes at start. If the user remove all scopes, we re-add those scopes, by security
|
||||||
|
scopesAtStart: accompanyingCourse.scopes.map(scope => scope),
|
||||||
|
// the scope states at server side
|
||||||
|
scopesAtBackend: accompanyingCourse.scopes.map(scope => scope),
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
isParticipationValid(state) {
|
isParticipationValid(state) {
|
||||||
@ -34,11 +47,16 @@ let initPromise = getAccompanyingCourse(id)
|
|||||||
isLocationValid(state) {
|
isLocationValid(state) {
|
||||||
return state.accompanyingCourse.location !== null;
|
return state.accompanyingCourse.location !== null;
|
||||||
},
|
},
|
||||||
|
isScopeValid(state) {
|
||||||
|
console.log('is scope valid', state.accompanyingCourse.scopes.length > 0);
|
||||||
|
return state.accompanyingCourse.scopes.length > 0;
|
||||||
|
},
|
||||||
validationKeys(state, getters) {
|
validationKeys(state, getters) {
|
||||||
let keys = [];
|
let keys = [];
|
||||||
if (!getters.isParticipationValid) { keys.push('participation'); }
|
if (!getters.isParticipationValid) { keys.push('participation'); }
|
||||||
if (!getters.isLocationValid) { keys.push('location'); }
|
if (!getters.isLocationValid) { keys.push('location'); }
|
||||||
if (!getters.isSocialIssueValid) { keys.push('socialIssue'); }
|
if (!getters.isSocialIssueValid) { keys.push('socialIssue'); }
|
||||||
|
if (!getters.isScopeValid) { keys.push('scopes'); }
|
||||||
//console.log('getter keys', keys);
|
//console.log('getter keys', keys);
|
||||||
return keys;
|
return keys;
|
||||||
},
|
},
|
||||||
@ -137,6 +155,21 @@ let initPromise = getAccompanyingCourse(id)
|
|||||||
setEditContextTrue(state) {
|
setEditContextTrue(state) {
|
||||||
//console.log('### mutation: set edit context = true');
|
//console.log('### mutation: set edit context = true');
|
||||||
state.addressContext.edit = true;
|
state.addressContext.edit = true;
|
||||||
|
},
|
||||||
|
setScopes(state, scopes) {
|
||||||
|
state.accompanyingCourse.scopes = scopes;
|
||||||
|
},
|
||||||
|
addScopeAtBackend(state, scope) {
|
||||||
|
let scopeIds = state.scopesAtBackend.map(s => s.id);
|
||||||
|
if (!scopeIds.includes(scope.id)) {
|
||||||
|
state.scopesAtBackend.push(scope);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeScopeAtBackend(state, scope){
|
||||||
|
let scopeIds = state.scopesAtBackend.map(s => s.id);
|
||||||
|
if (scopeIds.includes(scope.id)) {
|
||||||
|
state.scopesAtBackend = state.scopesAtBackend.filter(s => s.id !== scope.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@ -223,6 +256,107 @@ let initPromise = getAccompanyingCourse(id)
|
|||||||
resolve();
|
resolve();
|
||||||
})).catch((error) => { commit('catchError', error) });
|
})).catch((error) => { commit('catchError', error) });
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Handle the checked/unchecked scopes
|
||||||
|
*
|
||||||
|
* When the user set the scopes in a invalid situation (when no scopes are cheched), this
|
||||||
|
* method will internally re-add the scopes as they were originally when the page was loaded, but
|
||||||
|
* this does not appears for the user (they remains unchecked). When the user re-add a scope, the
|
||||||
|
* scope is back in a valid state, and the store synchronize with the new state (all the original scopes
|
||||||
|
* are removed if necessary, and the new checked scopes is backed).
|
||||||
|
*
|
||||||
|
* So, for instance:
|
||||||
|
*
|
||||||
|
* at load:
|
||||||
|
*
|
||||||
|
* [x] scope A (at backend: [x])
|
||||||
|
* [x] scope B (at backend: [x])
|
||||||
|
* [ ] scope C (at backend: [ ])
|
||||||
|
*
|
||||||
|
* The user uncheck scope A:
|
||||||
|
*
|
||||||
|
* [ ] scope A (at backend: [ ] as soon as the operation finish)
|
||||||
|
* [x] scope B (at backend: [x])
|
||||||
|
* [ ] scope C (at backend: [ ])
|
||||||
|
*
|
||||||
|
* The user uncheck scope B. The state is invalid (no scope checked), so we go back to initial state when
|
||||||
|
* the page loaded):
|
||||||
|
*
|
||||||
|
* [ ] scope A (at backend: [x] as soon as the operation finish)
|
||||||
|
* [ ] scope B (at backend: [x] as soon as the operation finish)
|
||||||
|
* [ ] scope C (at backend: [ ])
|
||||||
|
*
|
||||||
|
* The user check scope C. The scopes are back to valid state. So we go back to synchronization with UI and
|
||||||
|
* backend):
|
||||||
|
*
|
||||||
|
* [ ] scope A (at backend: [ ] as soon as the operation finish)
|
||||||
|
* [ ] scope B (at backend: [ ] as soon as the operation finish)
|
||||||
|
* [x] scope C (at backend: [x] as soon as the operation finish)
|
||||||
|
*
|
||||||
|
* **Warning** There is a problem if the user check/uncheck faster than the backend is synchronized.
|
||||||
|
*
|
||||||
|
* @param commit
|
||||||
|
* @param state
|
||||||
|
* @param dispatch
|
||||||
|
* @param scopes
|
||||||
|
* @returns Promise
|
||||||
|
*/
|
||||||
|
setScopes({ commit, state, dispatch }, scopes) {
|
||||||
|
let currentServerScopesIds = state.scopesAtBackend.map(scope => scope.id);
|
||||||
|
let checkedScopesIds = scopes.map(scope => scope.id);
|
||||||
|
let removedScopesIds = currentServerScopesIds.filter(id => !checkedScopesIds.includes(id));
|
||||||
|
let addedScopesIds = checkedScopesIds.filter(id => !currentServerScopesIds.includes(id));
|
||||||
|
let lengthAfterOperation = currentServerScopesIds.length + addedScopesIds.length
|
||||||
|
- removedScopesIds.length;
|
||||||
|
|
||||||
|
if (lengthAfterOperation > 0 || (lengthAfterOperation === 0 && state.scopesAtStart.length === 0) ) {
|
||||||
|
return dispatch('updateScopes', {
|
||||||
|
addedScopesIds, removedScopesIds
|
||||||
|
}).then(() => {
|
||||||
|
// warning: when the operation of dispatch are too slow, the user may check / uncheck before
|
||||||
|
// the end of the synchronisation with the server (done by dispatch operation). Then, it leads to
|
||||||
|
// check/uncheck in the UI. I do not know of to avoid it.
|
||||||
|
commit('setScopes', scopes);
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return dispatch('setScopes', state.scopesAtStart).then(() => {
|
||||||
|
commit('setScopes', scopes);
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Internal function for the store to effectively update scopes.
|
||||||
|
*
|
||||||
|
* Return a promise which resolves when all update operation are
|
||||||
|
* successful and finished.
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
* @param commit
|
||||||
|
* @param addedScopesIds
|
||||||
|
* @param removedScopesIds
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
updateScopes({ state, commit }, { addedScopesIds, removedScopesIds }) {
|
||||||
|
let promises = [];
|
||||||
|
state.scopes.forEach(scope => {
|
||||||
|
if (addedScopesIds.includes(scope.id)) {
|
||||||
|
promises.push(addScope(state.accompanyingCourse.id, scope).then(() => {
|
||||||
|
commit('addScopeAtBackend', scope);
|
||||||
|
return Promise.resolve();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
if (removedScopesIds.includes(scope.id)) {
|
||||||
|
promises.push(removeScope(state.accompanyingCourse.id, scope).then(() => {
|
||||||
|
commit('removeScopeAtBackend', scope);
|
||||||
|
return Promise.resolve();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises);
|
||||||
|
},
|
||||||
postFirstComment({ commit }, payload) {
|
postFirstComment({ commit }, payload) {
|
||||||
//console.log('## action: postFirstComment: payload', payload);
|
//console.log('## action: postFirstComment: payload', payload);
|
||||||
patchAccompanyingCourse(id, { type: "accompanying_period", initialComment: payload })
|
patchAccompanyingCourse(id, { type: "accompanying_period", initialComment: payload })
|
||||||
|
Loading…
x
Reference in New Issue
Block a user