mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge branch 'issue332_location_activity' into 'master'
fix: add availableForUsers condition from locationType in the location API endpoint See merge request Chill-Projet/chill-bundles!264
This commit is contained in:
commit
decc74c040
17
CHANGELOG.md
17
CHANGELOG.md
@ -10,10 +10,17 @@ and this project adheres to
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
<!-- write down unreleased development here -->
|
||||||
* [asideactivity] creation of aside activity category fixed (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/262)
|
* [asideactivity] creation of aside activity category fixed (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/262)
|
||||||
* [vendee/person] fix typo "situation professionelle" => "situation professionnelle"
|
* [vendee/person] fix typo "situation professionelle" => "situation professionnelle"
|
||||||
|
* [main] add availableForUsers condition from locationType in the location API endpoint (champs-libres/departement-de-la-vendee/accent-suivi-developpement#248)
|
||||||
<!-- write down unreleased development here -->
|
* [main] add the current location of the user as API point + add it in the activity location list (champs-libres/departement-de-la-vendee/accent-suivi-developpement#247)
|
||||||
|
* [activity] improve show/new/edit templates, fix SEE and SEE_DETAILS acl
|
||||||
|
* [badges] create specific badge for TMS, and make person/thirdparty badges clickable with on-the-fly modal in :
|
||||||
|
* concerned groups items (activity, calendar)
|
||||||
|
* accompanyingCourseWork lists
|
||||||
|
* accompanyingCourse lists
|
||||||
|
* [acompanyingCourse] add initial comment on Resume page
|
||||||
|
|
||||||
## Test releases
|
## Test releases
|
||||||
|
|
||||||
@ -37,12 +44,6 @@ and this project adheres to
|
|||||||
* [person] add death information in person render box in twig and vue render boxes (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/191)
|
* [person] add death information in person render box in twig and vue render boxes (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/191)
|
||||||
* [badge-entity] design coherency between pills badge-person and 3 kinds of badge-thirdparty
|
* [badge-entity] design coherency between pills badge-person and 3 kinds of badge-thirdparty
|
||||||
* [AddPersons] suggestions row are clickable, not only checkbox
|
* [AddPersons] suggestions row are clickable, not only checkbox
|
||||||
* [activity] improve show/new/edit templates, fix SEE and SEE_DETAILS acl
|
|
||||||
* [badges] create specific badge for TMS, and make person/thirdparty badges clickable with on-the-fly modal in :
|
|
||||||
* concerned groups items (activity, calendar)
|
|
||||||
* accompanyingCourseWork lists
|
|
||||||
* accompanyingCourse lists
|
|
||||||
* [acompanyingCourse] add initial comment on Resume page
|
|
||||||
|
|
||||||
|
|
||||||
### test release 2021-12-06
|
### test release 2021-12-06
|
||||||
|
@ -17,6 +17,14 @@ const getLocations = () => fetchResults('/api/1.0/main/location.json');
|
|||||||
|
|
||||||
const getLocationTypes = () => fetchResults('/api/1.0/main/location-type.json');
|
const getLocationTypes = () => fetchResults('/api/1.0/main/location-type.json');
|
||||||
|
|
||||||
|
const getUserCurrentLocation =
|
||||||
|
() => fetch('/api/1.0/main/user-current-location.json')
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) { return response.json(); }
|
||||||
|
throw Error('Error with request resource response');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load Location Type by defaultFor
|
* Load Location Type by defaultFor
|
||||||
* @param {string} entity - can be "person" or "thirdparty"
|
* @param {string} entity - can be "person" or "thirdparty"
|
||||||
@ -48,5 +56,6 @@ export {
|
|||||||
getLocations,
|
getLocations,
|
||||||
getLocationTypes,
|
getLocationTypes,
|
||||||
getLocationTypeByDefaultFor,
|
getLocationTypeByDefaultFor,
|
||||||
postLocation
|
postLocation,
|
||||||
|
getUserCurrentLocation
|
||||||
};
|
};
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
:searchable="true"
|
:searchable="true"
|
||||||
:placeholder="$t('activity.choose_location')"
|
:placeholder="$t('activity.choose_location')"
|
||||||
:custom-label="customLabel"
|
:custom-label="customLabel"
|
||||||
:options="locations"
|
:options="availableLocations"
|
||||||
group-values="locations"
|
group-values="locations"
|
||||||
group-label="locationGroup"
|
group-label="locationGroup"
|
||||||
v-model="location"
|
v-model="location"
|
||||||
@ -32,7 +32,7 @@
|
|||||||
import { mapState, mapGetters } from "vuex";
|
import { mapState, mapGetters } from "vuex";
|
||||||
import VueMultiselect from "vue-multiselect";
|
import VueMultiselect from "vue-multiselect";
|
||||||
import NewLocation from "./Location/NewLocation.vue";
|
import NewLocation from "./Location/NewLocation.vue";
|
||||||
import { getLocations, getLocationTypeByDefaultFor } from "../api.js";
|
import { getLocations, getLocationTypeByDefaultFor, getUserCurrentLocation } from "../api.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Location",
|
name: "Location",
|
||||||
@ -40,13 +40,8 @@ export default {
|
|||||||
NewLocation,
|
NewLocation,
|
||||||
VueMultiselect,
|
VueMultiselect,
|
||||||
},
|
},
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
locations: [],
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["activity"]),
|
...mapState(["activity", "availableLocations"]),
|
||||||
...mapGetters(["suggestedEntities"]),
|
...mapGetters(["suggestedEntities"]),
|
||||||
location: {
|
location: {
|
||||||
get() {
|
get() {
|
||||||
@ -57,53 +52,6 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
getLocations().then(
|
|
||||||
(results) => {
|
|
||||||
getLocationTypeByDefaultFor('person').then(
|
|
||||||
(personLocationType) => {
|
|
||||||
if (personLocationType) {
|
|
||||||
const personLocation = this.makeAccompanyingPeriodLocation(personLocationType);
|
|
||||||
const concernedPersonsLocation =
|
|
||||||
this.makeConcernedPersonsLocation(personLocationType);
|
|
||||||
getLocationTypeByDefaultFor('thirdparty').then(
|
|
||||||
thirdpartyLocationType => {
|
|
||||||
const concernedThirdPartiesLocation =
|
|
||||||
this.makeConcernedThirdPartiesLocation(thirdpartyLocationType);
|
|
||||||
this.locations = [
|
|
||||||
{
|
|
||||||
locationGroup: 'Localisation du parcours',
|
|
||||||
locations: [personLocation]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
locationGroup: 'Parties concernées',
|
|
||||||
locations: [...concernedPersonsLocation, ...concernedThirdPartiesLocation]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
locationGroup: 'Autres localisations',
|
|
||||||
locations: results
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
this.locations = [
|
|
||||||
{
|
|
||||||
locationGroup: 'Localisations',
|
|
||||||
locations: response.results
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
if (window.default_location_id) {
|
|
||||||
let location = this.locations.filter(
|
|
||||||
(l) => l.id === window.default_location_id
|
|
||||||
);
|
|
||||||
this.$store.dispatch("updateLocation", location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
labelAccompanyingCourseLocation(value) {
|
labelAccompanyingCourseLocation(value) {
|
||||||
return `${value.address.text} (${value.locationType.title.fr})`
|
return `${value.address.text} (${value.locationType.title.fr})`
|
||||||
@ -117,58 +65,6 @@ export default {
|
|||||||
: value.locationType.title.fr
|
: value.locationType.title.fr
|
||||||
: '';
|
: '';
|
||||||
},
|
},
|
||||||
makeConcernedPersonsLocation(locationType) {
|
|
||||||
let locations = [];
|
|
||||||
this.suggestedEntities.forEach(
|
|
||||||
(e) => {
|
|
||||||
if (e.type === 'person' && e.current_household_address !== null){
|
|
||||||
locations.push({
|
|
||||||
type: 'location',
|
|
||||||
id: -this.suggestedEntities.indexOf(e)*10,
|
|
||||||
onthefly: true,
|
|
||||||
name: e.text,
|
|
||||||
address: {
|
|
||||||
id: e.current_household_address.address_id,
|
|
||||||
},
|
|
||||||
locationType: locationType
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return locations;
|
|
||||||
},
|
|
||||||
makeConcernedThirdPartiesLocation(locationType) {
|
|
||||||
let locations = [];
|
|
||||||
this.suggestedEntities.forEach(
|
|
||||||
(e) => {
|
|
||||||
if (e.type === 'thirdparty' && e.address !== null){
|
|
||||||
locations.push({
|
|
||||||
type: 'location',
|
|
||||||
id: -this.suggestedEntities.indexOf(e)*10,
|
|
||||||
onthefly: true,
|
|
||||||
name: e.text,
|
|
||||||
address: { id: e.address.address_id },
|
|
||||||
locationType: locationType
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return locations;
|
|
||||||
},
|
|
||||||
makeAccompanyingPeriodLocation(locationType) {
|
|
||||||
const accPeriodLocation = this.activity.accompanyingPeriod.location;
|
|
||||||
return {
|
|
||||||
type: 'location',
|
|
||||||
id: -1,
|
|
||||||
onthefly: true,
|
|
||||||
name: '__AccompanyingCourseLocation__',
|
|
||||||
address: {
|
|
||||||
id: accPeriodLocation.address_id,
|
|
||||||
text: `${accPeriodLocation.text} - ${accPeriodLocation.postcode.code} ${accPeriodLocation.postcode.name}`
|
|
||||||
},
|
|
||||||
locationType: locationType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'es6-promise/auto';
|
import 'es6-promise/auto';
|
||||||
import { createStore } from 'vuex';
|
import { createStore } from 'vuex';
|
||||||
import { postLocation } from './api';
|
import { postLocation } from './api';
|
||||||
|
import prepareLocations from './store.locations.js';
|
||||||
|
|
||||||
const debug = process.env.NODE_ENV !== 'production';
|
const debug = process.env.NODE_ENV !== 'production';
|
||||||
//console.log('window.activity', window.activity);
|
//console.log('window.activity', window.activity);
|
||||||
@ -25,6 +26,7 @@ const store = createStore({
|
|||||||
activity: window.activity,
|
activity: window.activity,
|
||||||
socialIssuesOther: [],
|
socialIssuesOther: [],
|
||||||
socialActionsList: [],
|
socialActionsList: [],
|
||||||
|
availableLocations: [],
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
suggestedEntities(state) {
|
suggestedEntities(state) {
|
||||||
@ -200,6 +202,9 @@ const store = createStore({
|
|||||||
console.log("### mutation: updateLocation", value);
|
console.log("### mutation: updateLocation", value);
|
||||||
state.activity.location = value;
|
state.activity.location = value;
|
||||||
},
|
},
|
||||||
|
addAvailableLocationGroup(state, group) {
|
||||||
|
state.availableLocations.push(group);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
addIssueSelected({ commit }, issue) {
|
addIssueSelected({ commit }, issue) {
|
||||||
@ -335,4 +340,6 @@ const store = createStore({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
prepareLocations(store);
|
||||||
|
|
||||||
export default store;
|
export default store;
|
||||||
|
@ -0,0 +1,123 @@
|
|||||||
|
import {getLocations, getLocationTypeByDefaultFor, getUserCurrentLocation} from "./api";
|
||||||
|
|
||||||
|
const makeConcernedPersonsLocation = (locationType, store) => {
|
||||||
|
let locations = [];
|
||||||
|
store.getters.suggestedEntities.forEach(
|
||||||
|
(e) => {
|
||||||
|
if (e.type === 'person' && e.current_household_address !== null){
|
||||||
|
locations.push({
|
||||||
|
type: 'location',
|
||||||
|
id: -store.getters.suggestedEntities.indexOf(e)*10,
|
||||||
|
onthefly: true,
|
||||||
|
name: e.text,
|
||||||
|
address: {
|
||||||
|
id: e.current_household_address.address_id,
|
||||||
|
},
|
||||||
|
locationType: locationType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return locations;
|
||||||
|
};
|
||||||
|
const makeConcernedThirdPartiesLocation = (locationType, store) => {
|
||||||
|
let locations = [];
|
||||||
|
store.getters.suggestedEntities.forEach(
|
||||||
|
(e) => {
|
||||||
|
if (e.type === 'thirdparty' && e.address !== null){
|
||||||
|
locations.push({
|
||||||
|
type: 'location',
|
||||||
|
id: -store.getters.suggestedEntities.indexOf(e)*10,
|
||||||
|
onthefly: true,
|
||||||
|
name: e.text,
|
||||||
|
address: { id: e.address.address_id },
|
||||||
|
locationType: locationType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return locations;
|
||||||
|
};
|
||||||
|
const makeAccompanyingPeriodLocation = (locationType, store) => {
|
||||||
|
const accPeriodLocation = store.state.activity.accompanyingPeriod.location;
|
||||||
|
return {
|
||||||
|
type: 'location',
|
||||||
|
id: -1,
|
||||||
|
onthefly: true,
|
||||||
|
name: '__AccompanyingCourseLocation__',
|
||||||
|
address: {
|
||||||
|
id: accPeriodLocation.address_id,
|
||||||
|
text: `${accPeriodLocation.text} - ${accPeriodLocation.postcode.code} ${accPeriodLocation.postcode.name}`
|
||||||
|
},
|
||||||
|
locationType: locationType
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function prepareLocations(store) {
|
||||||
|
|
||||||
|
// find the locations
|
||||||
|
let allLocations = getLocations().then(
|
||||||
|
(results) => {
|
||||||
|
store.commit('addAvailableLocationGroup', {
|
||||||
|
locationGroup: 'Autres localisations',
|
||||||
|
locations: results
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let currentLocation = getUserCurrentLocation().then(
|
||||||
|
userCurrentLocation => {
|
||||||
|
if (null !== userCurrentLocation) {
|
||||||
|
store.commit('addAvailableLocationGroup', {
|
||||||
|
locationGroup: 'Ma localisation',
|
||||||
|
locations: [userCurrentLocation]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let partiesLocations = [], partyPromise;
|
||||||
|
['person', 'thirdparty'].forEach(kind => {
|
||||||
|
partyPromise = getLocationTypeByDefaultFor(kind).then(
|
||||||
|
(kindLocationType) => {
|
||||||
|
if (kindLocationType) {
|
||||||
|
let concernedKindLocations;
|
||||||
|
if (kind === 'person') {
|
||||||
|
concernedKindLocations = makeConcernedPersonsLocation(kindLocationType, store);
|
||||||
|
// add location for the parcours into suggestions
|
||||||
|
const personLocation = makeAccompanyingPeriodLocation(kindLocationType, store);
|
||||||
|
store.commit('addAvailableLocationGroup', {
|
||||||
|
locationGroup: 'Localisation du parcours',
|
||||||
|
locations: [personLocation]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
concernedKindLocations = makeConcernedThirdPartiesLocation(kindLocationType, store);
|
||||||
|
}
|
||||||
|
|
||||||
|
store.commit('addAvailableLocationGroup', {
|
||||||
|
locationGroup: kind === 'person' ? 'Usagers concernés' : 'Tiers concernés',
|
||||||
|
locations: concernedKindLocations,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
partiesLocations.push(partyPromise);
|
||||||
|
});
|
||||||
|
|
||||||
|
// when all location are loaded
|
||||||
|
Promise.all([allLocations, currentLocation, ...partiesLocations]).then(() => {
|
||||||
|
console.log('current location in activity', store.state.activity.location);
|
||||||
|
console.log('default loation id', window.default_location_id);
|
||||||
|
if (window.default_location_id) {
|
||||||
|
for (let group of store.state.availableLocations) {
|
||||||
|
console.log(group);
|
||||||
|
let location = group.locations.find((l) => l.id === window.default_location_id);
|
||||||
|
console.log(location);
|
||||||
|
if (location !== undefined) {
|
||||||
|
store.dispatch('updateLocation', location);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
@ -1,6 +1,10 @@
|
|||||||
import 'es6-promise/auto';
|
import 'es6-promise/auto';
|
||||||
import { createStore } from 'vuex';
|
import { createStore } from 'vuex';
|
||||||
import { postLocation } from 'ChillActivityAssets/vuejs/Activity/api';
|
import { postLocation } from 'ChillActivityAssets/vuejs/Activity/api';
|
||||||
|
import {
|
||||||
|
getLocations, getLocationTypeByDefaultFor,
|
||||||
|
getUserCurrentLocation
|
||||||
|
} from "../../../../../ChillActivityBundle/Resources/public/vuejs/Activity/api";
|
||||||
|
|
||||||
const debug = process.env.NODE_ENV !== 'production';
|
const debug = process.env.NODE_ENV !== 'production';
|
||||||
|
|
||||||
@ -217,9 +221,7 @@ const store = createStore({
|
|||||||
hiddenLocation.value = value.id;
|
hiddenLocation.value = value.id;
|
||||||
}
|
}
|
||||||
commit("updateLocation", value);
|
commit("updateLocation", value);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -21,11 +21,14 @@ class LocationApiController extends ApiController
|
|||||||
{
|
{
|
||||||
public function customizeQuery(string $action, Request $request, $query): void
|
public function customizeQuery(string $action, Request $request, $query): void
|
||||||
{
|
{
|
||||||
$query->andWhere(
|
$query
|
||||||
$query->expr()->andX(
|
->leftJoin('e.locationType', 'lt')
|
||||||
|
->andWhere(
|
||||||
|
$query->expr()->andX(
|
||||||
$query->expr()->eq('e.availableForUsers', "'TRUE'"),
|
$query->expr()->eq('e.availableForUsers', "'TRUE'"),
|
||||||
|
$query->expr()->eq('lt.availableForUsers', "'TRUE'"),
|
||||||
$query->expr()->eq('e.active', "'TRUE'"),
|
$query->expr()->eq('e.active', "'TRUE'"),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,27 @@ use Symfony\Component\Routing\Annotation\Route;
|
|||||||
|
|
||||||
class UserApiController extends ApiController
|
class UserApiController extends ApiController
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @Route(
|
||||||
|
* "/api/1.0/main/user-current-location.{_format}",
|
||||||
|
* name="chill_main_user_current_location",
|
||||||
|
* requirements={
|
||||||
|
* "_format": "json"
|
||||||
|
* }
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* @param mixed $_format
|
||||||
|
*/
|
||||||
|
public function currentLocation($_format): JsonResponse
|
||||||
|
{
|
||||||
|
return $this->json(
|
||||||
|
$this->getUser()->getCurrentLocation(),
|
||||||
|
JsonResponse::HTTP_OK,
|
||||||
|
[],
|
||||||
|
['groups' => ['read']]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route(
|
* @Route(
|
||||||
* "/api/1.0/main/whoami.{_format}",
|
* "/api/1.0/main/whoami.{_format}",
|
||||||
|
@ -55,6 +55,15 @@ final class UserApiControllerTest extends WebTestCase
|
|||||||
return $data['results'][0];
|
return $data['results'][0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testUserCurrentLocation()
|
||||||
|
{
|
||||||
|
$client = $this->getClientAuthenticated();
|
||||||
|
|
||||||
|
$client->request(Request::METHOD_GET, '/api/1.0/main/user-current-location.json');
|
||||||
|
|
||||||
|
$this->assertResponseIsSuccessful();
|
||||||
|
}
|
||||||
|
|
||||||
public function testWhoami()
|
public function testWhoami()
|
||||||
{
|
{
|
||||||
$client = $this->getClientAuthenticated();
|
$client = $this->getClientAuthenticated();
|
||||||
|
@ -546,6 +546,14 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: "ok"
|
description: "ok"
|
||||||
|
/1.0/main/user-current-location.json:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
summary: Return the current location of the currently authenticated user
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "ok"
|
||||||
/1.0/main/user/{id}.json:
|
/1.0/main/user/{id}.json:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user