Merge branch 'ticket/supplementary-comments-on-motive' into 'master'

Ajout de commentaires supplémentaires aux motifs

See merge request Chill-Projet/chill-bundles!855
This commit is contained in:
2025-07-11 14:06:40 +00:00
392 changed files with 35466 additions and 24054 deletions

View File

@@ -0,0 +1,6 @@
kind: Feature
body: |
Upgrade import of address list to the last version of compiled addresses of belgian-best-address
time: 2024-05-30T16:00:03.440767606+02:00
custom:
Issue: ""

View File

@@ -0,0 +1,6 @@
kind: Feature
body: |
Upgrade CKEditor and refactor configuration with use of typescript
time: 2024-05-31T19:02:42.776662753+02:00
custom:
Issue: ""

View File

@@ -23,7 +23,7 @@ max_line_length = 0
indent_size = 2 indent_size = 2
indent_style = space indent_style = space
[.rst] [*.rst]
ident_size = 3 indent_size = 3
ident_style = space indent_style = space

File diff suppressed because it is too large Load Diff

4
.prettierrc Normal file
View File

@@ -0,0 +1,4 @@
{
"tabWidth": 2,
"useTabs": false
}

30
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,30 @@
{
// Use IntelliSense to learn about possible attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Chill Debug",
"type": "php",
"request": "launch",
"port": 9000,
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
},
"preLaunchTask": "symfony"
},
{
"name": "Yarn Encore Dev (Watch)",
"type": "node-terminal",
"request": "launch",
"command": "yarn encore dev --watch",
"cwd": "${workspaceFolder}"
}
],
"compounds": [
{
"name": "Chill Debug + Yarn Encore Dev (Watch)",
"configurations": ["Chill Debug", "Yarn Encore Dev (Watch)"]
}
]
}

23
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,23 @@
{
"tasks": [
{
"type": "shell",
"command": "symfony",
"args": [
"server:start",
"--allow-http",
"--no-tls",
"--port=8000",
"--allow-all-ip",
"-d"
],
"label": "symfony"
},
{
"type": "shell",
"command": "yarn",
"args": ["encore", "dev", "--watch"],
"label": "webpack"
}
]
}

View File

@@ -54,7 +54,7 @@ Arborescence:
- person - person
- personvendee - personvendee
- household_edit_metadata - household_edit_metadata
- index.js - index.ts
``` ```
## Organisation des feuilles de styles ## Organisation des feuilles de styles

View File

@@ -133,6 +133,7 @@
"Chill\\TaskBundle\\": "src/Bundle/ChillTaskBundle", "Chill\\TaskBundle\\": "src/Bundle/ChillTaskBundle",
"Chill\\ThirdPartyBundle\\": "src/Bundle/ChillThirdPartyBundle", "Chill\\ThirdPartyBundle\\": "src/Bundle/ChillThirdPartyBundle",
"Chill\\WopiBundle\\": "src/Bundle/ChillWopiBundle/src", "Chill\\WopiBundle\\": "src/Bundle/ChillWopiBundle/src",
"Chill\\TicketBundle\\": "src/Bundle/ChillTicketBundle/src",
"Chill\\Utils\\Rector\\": "utils/rector/src" "Chill\\Utils\\Rector\\": "utils/rector/src"
} }
}, },

View File

@@ -35,6 +35,7 @@ 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],
]; ];

View File

@@ -0,0 +1,4 @@
chill_ticket:
ticket:
person_per_ticket: one # One of "one"; "many"

View File

@@ -14,6 +14,7 @@ doctrine_migrations:
'Chill\Migrations\Calendar': '@ChillCalendarBundle/migrations' 'Chill\Migrations\Calendar': '@ChillCalendarBundle/migrations'
'Chill\Migrations\Budget': '@ChillBudgetBundle/migrations' 'Chill\Migrations\Budget': '@ChillBudgetBundle/migrations'
'Chill\Migrations\Report': '@ChillReportBundle/migrations' 'Chill\Migrations\Report': '@ChillReportBundle/migrations'
'Chill\Migrations\Ticket': '@ChillTicketBundle/migrations'
all_or_nothing: all_or_nothing:
true true

View File

@@ -0,0 +1,2 @@
chill_ticket_bundle:
resource: '@ChillTicketBundle/config/routes.yaml'

View File

@@ -11,24 +11,94 @@
Create a new bundle Create a new bundle
******************* *******************
Create your own bundle is not a trivial task.
The easiest way to achieve this is seems to be :
1. Prepare a fresh installation of the chill project, in a new directory
2. Create a new bundle in this project, in the src directory
3. Initialize a git repository **at the root bundle**, and create your initial commit.
4. Register the bundle with composer/packagist. If you do not plan to distribute your bundle with packagist, you may use a custom repository for achieve this [#f1]_
5. Move to a development installation, made as described in the :ref:`installation-for-development` section, and add your new repository to the composer.json file
6. Work as :ref:`usual <editing-code-and-commiting>`
.. warning:: .. warning::
This part of the doc is not yet tested This part of the doc is not yet tested
TODO Create a new directory with Bundle class
----------------------------------------
.. code-block:: bash
mkdir -p src/Bundle/ChillSomeBundle/src/config
mkdir -p src/Bundle/ChillSomeBundle/src/Controller
Add a bundle file
.. code-block:: php
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\SomeBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ChillSomeBundle extends Bundle {}
And a route file:
.. code-block:: yaml
chill_ticket_controller:
resource: '@ChillTicketBundle/Controller/'
type: annotation
Register the new psr-4 namespace
--------------------------------
In composer.json, add the new psr4 namespace
.. code-block:: diff
{
"autoload": {
"psr-4": {
+ "Chill\\SomeBundle\\": "src/Bundle/ChillSomeBundle/src",
}
}
}
.. rubric:: Footnotes Register the bundle
-------------------
Register in the file :code:`config/bundles.php`:
.. code-block:: php
Vendor\Bundle\YourBundle\YourBundle::class => ['all' => true],
And import routes in :code:`config/routes/chill_some_bundle.yaml`:
.. code-block:: yaml
chill_ticket_bundle:
resource: '@ChillSomeBundle/config/routes.yaml'
Add the doctrine_migration namespace
------------------------------------
Add the namespace to :code:`config/packages/doctrine_migrations_chill.yaml`
.. code-block:: diff
doctrine_migrations:
migrations_paths:
+ 'Chill\Some\Ticket': '@ChillSomeBundle/migrations'
Dump autoloading
----------------
.. code-block:: bash
symfony composer dump-autoload
.. [#f1] Be aware that we use the Affero GPL Licence, which ensure that all users must have access to derivative works done with this software.

View File

@@ -79,12 +79,12 @@
"dev": "encore dev", "dev": "encore dev",
"watch": "encore dev --watch", "watch": "encore dev --watch",
"build": "encore production --progress", "build": "encore production --progress",
"specs-build": "yaml-merge src/Bundle/ChillMainBundle/chill.api.specs.yaml src/Bundle/ChillPersonBundle/chill.api.specs.yaml src/Bundle/ChillCalendarBundle/chill.api.specs.yaml src/Bundle/ChillThirdPartyBundle/chill.api.specs.yaml src/Bundle/ChillDocStoreBundle/chill.api.specs.yaml> templates/api/specs.yaml", "specs-build": "yaml-merge src/Bundle/ChillMainBundle/chill.api.specs.yaml src/Bundle/ChillPersonBundle/chill.api.specs.yaml src/Bundle/ChillCalendarBundle/chill.api.specs.yaml src/Bundle/ChillThirdPartyBundle/chill.api.specs.yaml src/Bundle/ChillDocStoreBundle/chill.api.specs.yaml src/Bundle/ChillTicketBundle/chill.api.specs.yaml> templates/api/specs.yaml",
"specs-validate": "swagger-cli validate templates/api/specs.yaml", "specs-validate": "swagger-cli validate templates/api/specs.yaml",
"specs-create-dir": "mkdir -p templates/api", "specs-create-dir": "mkdir -p templates/api",
"specs": "yarn run specs-create-dir && yarn run specs-build && yarn run specs-validate", "specs": "yarn run specs-create-dir && yarn run specs-build && yarn run specs-validate",
"version": "node --version", "version": "node --version",
"eslint": "npx eslint-baseline --fix \"src/**/*.{js,ts,vue}\"" "eslint": "eslint-baseline --fix \"src/**/*.{js,ts,vue}\""
}, },
"private": true "private": true
} }

View File

@@ -58,6 +58,10 @@
<!-- temporarily removed, the time to find a fix --> <!-- temporarily removed, the time to find a fix -->
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php</exclude> <exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php</exclude>
</testsuite> </testsuite>
<testsuite name="TicketBundle">
<directory suffix="Test.php">src/Bundle/ChillTicketBundle/tests/</directory>
</testsuite>
<!-- <!--
<testsuite name="ReportBundle"> <testsuite name="ReportBundle">
<directory suffix="Test.php">src/Bundle/ChillReportBundle/Tests/</directory> <directory suffix="Test.php">src/Bundle/ChillReportBundle/Tests/</directory>

View File

@@ -10,10 +10,7 @@
/> />
</div> </div>
<div <div
v-if=" v-if="getContext === 'accompanyingCourse' && suggestedEntities.length > 0"
getContext === 'accompanyingCourse' &&
suggestedEntities.length > 0
"
> >
<ul class="list-suggest add-items inline"> <ul class="list-suggest add-items inline">
<li <li

View File

@@ -39,17 +39,11 @@
<option selected disabled value=""> <option selected disabled value="">
{{ trans(ACTIVITY_CHOOSE_LOCATION_TYPE) }} {{ trans(ACTIVITY_CHOOSE_LOCATION_TYPE) }}
</option> </option>
<option <option v-for="t in locationTypes" :value="t" :key="t.id">
v-for="t in locationTypes"
:value="t"
:key="t.id"
>
{{ localizeString(t.title) }} {{ localizeString(t.title) }}
</option> </option>
</select> </select>
<label>{{ <label>{{ trans(ACTIVITY_LOCATION_FIELDS_TYPE) }}</label>
trans(ACTIVITY_LOCATION_FIELDS_TYPE)
}}</label>
</div> </div>
<div class="form-floating mb-3"> <div class="form-floating mb-3">
@@ -108,10 +102,7 @@
</form> </form>
</template> </template>
<template #footer> <template #footer>
<button <button class="btn btn-save" @click.prevent="saveNewLocation">
class="btn btn-save"
@click.prevent="saveNewLocation"
>
{{ trans(SAVE) }} {{ trans(SAVE) }}
</button> </button>
</template> </template>
@@ -244,8 +235,7 @@ export default {
}, },
hasPhonenumber1() { hasPhonenumber1() {
return ( return (
this.selected.phonenumber1 !== null && this.selected.phonenumber1 !== null && this.selected.phonenumber1 !== ""
this.selected.phonenumber1 !== ""
); );
}, },
showAddAddress() { showAddAddress() {

View File

@@ -49,9 +49,7 @@
</div> </div>
<div class="col-8"> <div class="col-8">
<div v-if="actionIsLoading === true"> <div v-if="actionIsLoading === true">
<i <i class="chill-green fa fa-circle-o-notch fa-spin fa-lg"></i>
class="chill-green fa fa-circle-o-notch fa-spin fa-lg"
></i>
</div> </div>
<span <span
@@ -64,8 +62,7 @@
<template <template
v-else-if=" v-else-if="
socialActionsList.length > 0 && socialActionsList.length > 0 &&
(socialIssuesSelected.length || (socialIssuesSelected.length || socialActionsSelected.length)
socialActionsSelected.length)
" "
> >
<div <div
@@ -88,9 +85,7 @@
</template> </template>
<span <span
v-else-if=" v-else-if="actionAreLoaded && socialActionsList.length === 0"
actionAreLoaded && socialActionsList.length === 0
"
class="inline-choice chill-no-data-statement mt-3" class="inline-choice chill-no-data-statement mt-3"
> >
{{ trans(ACTIVITY_SOCIAL_ACTION_LIST_EMPTY) }} {{ trans(ACTIVITY_SOCIAL_ACTION_LIST_EMPTY) }}
@@ -169,8 +164,7 @@ export default {
/* Add in list the issues already associated (if not yet listed) */ /* Add in list the issues already associated (if not yet listed) */
this.socialIssuesSelected.forEach((issue) => { this.socialIssuesSelected.forEach((issue) => {
if ( if (
this.socialIssuesList.filter((i) => i.id === issue.id) this.socialIssuesList.filter((i) => i.id === issue.id).length !== 1
.length !== 1
) { ) {
this.$store.commit("addIssueInList", issue); this.$store.commit("addIssueInList", issue);
} }

View File

@@ -10,9 +10,7 @@
:value="issue" :value="issue"
/> />
<label class="form-check-label" :for="issue.id"> <label class="form-check-label" :for="issue.id">
<span class="badge bg-chill-l-gray text-dark">{{ <span class="badge bg-chill-l-gray text-dark">{{ issue.text }}</span>
issue.text
}}</span>
</label> </label>
</div> </div>
</span> </span>

View File

@@ -68,9 +68,7 @@ export type EventInputCalendarRange = EventInput & {
export function isEventInputCalendarRange( export function isEventInputCalendarRange(
toBeDetermined: EventInputCalendarRange | EventInput, toBeDetermined: EventInputCalendarRange | EventInput,
): toBeDetermined is EventInputCalendarRange { ): toBeDetermined is EventInputCalendarRange {
return ( return typeof toBeDetermined.is === "string" && toBeDetermined.is === "range";
typeof toBeDetermined.is === "string" && toBeDetermined.is === "range"
);
} }
export {}; export {};

View File

@@ -61,22 +61,14 @@
<label class="input-group-text" for="slotDuration" <label class="input-group-text" for="slotDuration"
>Durée des créneaux</label >Durée des créneaux</label
> >
<select <select v-model="slotDuration" id="slotDuration" class="form-select">
v-model="slotDuration"
id="slotDuration"
class="form-select"
>
<option value="00:05:00">5 minutes</option> <option value="00:05:00">5 minutes</option>
<option value="00:10:00">10 minutes</option> <option value="00:10:00">10 minutes</option>
<option value="00:15:00">15 minutes</option> <option value="00:15:00">15 minutes</option>
<option value="00:30:00">30 minutes</option> <option value="00:30:00">30 minutes</option>
</select> </select>
<label class="input-group-text" for="slotMinTime">De</label> <label class="input-group-text" for="slotMinTime">De</label>
<select <select v-model="slotMinTime" id="slotMinTime" class="form-select">
v-model="slotMinTime"
id="slotMinTime"
class="form-select"
>
<option value="00:00:00">0h</option> <option value="00:00:00">0h</option>
<option value="01:00:00">1h</option> <option value="01:00:00">1h</option>
<option value="02:00:00">2h</option> <option value="02:00:00">2h</option>
@@ -92,11 +84,7 @@
<option value="12:00:00">12h</option> <option value="12:00:00">12h</option>
</select> </select>
<label class="input-group-text" for="slotMaxTime">À</label> <label class="input-group-text" for="slotMaxTime">À</label>
<select <select v-model="slotMaxTime" id="slotMaxTime" class="form-select">
v-model="slotMaxTime"
id="slotMaxTime"
class="form-select"
>
<option value="12:00:00">12h</option> <option value="12:00:00">12h</option>
<option value="13:00:00">13h</option> <option value="13:00:00">13h</option>
<option value="14:00:00">14h</option> <option value="14:00:00">14h</option>
@@ -124,9 +112,7 @@
v-model="hideWeekends" v-model="hideWeekends"
/> />
</span> </span>
<label <label for="showHideWE" class="form-check-label input-group-text"
for="showHideWE"
class="form-check-label input-group-text"
>Week-ends</label >Week-ends</label
> >
</div> </div>
@@ -142,9 +128,7 @@
<b v-else-if="arg.event.extendedProps.is === 'range'" <b v-else-if="arg.event.extendedProps.is === 'range'"
>{{ arg.timeText }} >{{ arg.timeText }}
{{ arg.event.extendedProps.locationName }} {{ arg.event.extendedProps.locationName }}
<small>{{ <small>{{ arg.event.extendedProps.userLabel }}</small></b
arg.event.extendedProps.userLabel
}}</small></b
> >
<b v-else-if="arg.event.extendedProps.is === 'current'" <b v-else-if="arg.event.extendedProps.is === 'current'"
>{{ arg.timeText }} {{ $t("current_selected") }} >{{ arg.timeText }} {{ $t("current_selected") }}
@@ -152,9 +136,7 @@
<b v-else-if="arg.event.extendedProps.is === 'local'">{{ <b v-else-if="arg.event.extendedProps.is === 'local'">{{
arg.event.title arg.event.title
}}</b> }}</b>
<b v-else <b v-else>{{ arg.timeText }} {{ $t("current_selected") }} </b>
>{{ arg.timeText }} {{ $t("current_selected") }}
</b>
</span> </span>
</template> </template>
</FullCalendar> </FullCalendar>
@@ -268,9 +250,7 @@ export default {
this.$store.state.activity.endDate !== null) this.$store.state.activity.endDate !== null)
) { ) {
if ( if (
!window.confirm( !window.confirm(this.$t("change_main_user_will_reset_event_data"))
this.$t("change_main_user_will_reset_event_data"),
)
) { ) {
return; return;
} }
@@ -278,13 +258,9 @@ export default {
// add the previous user, if any, in the previous user list (in use for suggestion) // add the previous user, if any, in the previous user list (in use for suggestion)
if (null !== this.$store.getters.getMainUser) { if (null !== this.$store.getters.getMainUser) {
const suggestedUids = new Set( const suggestedUids = new Set(this.$data.previousUser.map((u) => u.id));
this.$data.previousUser.map((u) => u.id),
);
if (!suggestedUids.has(this.$store.getters.getMainUser.id)) { if (!suggestedUids.has(this.$store.getters.getMainUser.id)) {
this.$data.previousUser.push( this.$data.previousUser.push(this.$store.getters.getMainUser);
this.$store.getters.getMainUser,
);
} }
} }
@@ -314,8 +290,7 @@ export default {
// show an alert if changing mainUser // show an alert if changing mainUser
if ( if (
(this.$store.getters.getMainUser !== null && (this.$store.getters.getMainUser !== null &&
this.$store.state.me.id !== this.$store.state.me.id !== this.$store.getters.getMainUser.id) ||
this.$store.getters.getMainUser.id) ||
this.$store.getters.getMainUser === null this.$store.getters.getMainUser === null
) { ) {
if (!window.confirm(this.$t("will_change_main_user_for_me"))) { if (!window.confirm(this.$t("will_change_main_user_for_me"))) {
@@ -359,9 +334,7 @@ export default {
this.$store.getters.getMainUser.id this.$store.getters.getMainUser.id
) { ) {
if ( if (
!window.confirm( !window.confirm(this.$t("this_calendar_range_will_change_main_user"))
this.$t("this_calendar_range_will_change_main_user"),
)
) { ) {
return; return;
} }

View File

@@ -4,18 +4,9 @@
{{ user.text }} {{ user.text }}
<template v-if="invite !== null"> <template v-if="invite !== null">
<i v-if="invite.status === 'accepted'" class="fa fa-check" /> <i v-if="invite.status === 'accepted'" class="fa fa-check" />
<i <i v-else-if="invite.status === 'declined'" class="fa fa-times" />
v-else-if="invite.status === 'declined'" <i v-else-if="invite.status === 'pending'" class="fa fa-question-o" />
class="fa fa-times" <i v-else-if="invite.status === 'tentative'" class="fa fa-question" />
/>
<i
v-else-if="invite.status === 'pending'"
class="fa fa-question-o"
/>
<i
v-else-if="invite.status === 'tentative'"
class="fa fa-question"
/>
<span v-else="">{{ invite.status }}</span> <span v-else="">{{ invite.status }}</span>
</template> </template>
</span> </span>
@@ -69,8 +60,7 @@ export default {
computed: { computed: {
style() { style() {
return { return {
backgroundColor: this.$store.getters.getUserData(this.user) backgroundColor: this.$store.getters.getUserData(this.user).mainColor,
.mainColor,
}; };
}, },
rangeShow: { rangeShow: {
@@ -81,9 +71,7 @@ export default {
}); });
}, },
get() { get() {
return this.$store.getters.isRangeShownOnCalendarForUser( return this.$store.getters.isRangeShownOnCalendarForUser(this.user);
this.user,
);
}, },
}, },
remoteShow: { remoteShow: {
@@ -94,9 +82,7 @@ export default {
}); });
}, },
get() { get() {
return this.$store.getters.isRemoteShownOnCalendarForUser( return this.$store.getters.isRemoteShownOnCalendarForUser(this.user);
this.user,
);
}, },
}, },
}, },

View File

@@ -22,33 +22,25 @@
</button> </button>
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1"> <ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
<li v-if="status !== Statuses.ACCEPTED"> <li v-if="status !== Statuses.ACCEPTED">
<a <a class="dropdown-item" @click="changeStatus(Statuses.ACCEPTED)"
class="dropdown-item" ><i class="fa fa-check" aria-hidden="true"></i> {{ $t("Accept") }}</a
@click="changeStatus(Statuses.ACCEPTED)"
><i class="fa fa-check" aria-hidden="true"></i>
{{ $t("Accept") }}</a
> >
</li> </li>
<li v-if="status !== Statuses.DECLINED"> <li v-if="status !== Statuses.DECLINED">
<a <a class="dropdown-item" @click="changeStatus(Statuses.DECLINED)"
class="dropdown-item" ><i class="fa fa-times" aria-hidden="true"></i> {{ $t("Decline") }}</a
@click="changeStatus(Statuses.DECLINED)"
><i class="fa fa-times" aria-hidden="true"></i>
{{ $t("Decline") }}</a
> >
</li> </li>
<li v-if="status !== Statuses.TENTATIVELY_ACCEPTED"> <li v-if="status !== Statuses.TENTATIVELY_ACCEPTED">
<a <a
class="dropdown-item" class="dropdown-item"
@click="changeStatus(Statuses.TENTATIVELY_ACCEPTED)" @click="changeStatus(Statuses.TENTATIVELY_ACCEPTED)"
><i class="fa fa-question"></i> ><i class="fa fa-question"></i> {{ $t("Tentatively_accept") }}</a
{{ $t("Tentatively_accept") }}</a
> >
</li> </li>
<li v-if="status !== Statuses.PENDING"> <li v-if="status !== Statuses.PENDING">
<a class="dropdown-item" @click="changeStatus(Statuses.PENDING)" <a class="dropdown-item" @click="changeStatus(Statuses.PENDING)"
><i class="fa fa-hourglass-o"></i> ><i class="fa fa-hourglass-o"></i> {{ $t("Set_pending") }}</a
{{ $t("Set_pending") }}</a
> >
</li> </li>
</ul> </ul>
@@ -91,9 +83,7 @@ export default defineComponent({
}, },
}, },
emits: { emits: {
statusChanged( statusChanged(payload: "accepted" | "declined" | "pending" | "tentative") {
payload: "accepted" | "declined" | "pending" | "tentative",
) {
return true; return true;
}, },
}, },

View File

@@ -23,22 +23,14 @@
<label class="input-group-text" for="slotDuration" <label class="input-group-text" for="slotDuration"
>Durée des créneaux</label >Durée des créneaux</label
> >
<select <select v-model="slotDuration" id="slotDuration" class="form-select">
v-model="slotDuration"
id="slotDuration"
class="form-select"
>
<option value="00:05:00">5 minutes</option> <option value="00:05:00">5 minutes</option>
<option value="00:10:00">10 minutes</option> <option value="00:10:00">10 minutes</option>
<option value="00:15:00">15 minutes</option> <option value="00:15:00">15 minutes</option>
<option value="00:30:00">30 minutes</option> <option value="00:30:00">30 minutes</option>
</select> </select>
<label class="input-group-text" for="slotMinTime">De</label> <label class="input-group-text" for="slotMinTime">De</label>
<select <select v-model="slotMinTime" id="slotMinTime" class="form-select">
v-model="slotMinTime"
id="slotMinTime"
class="form-select"
>
<option value="00:00:00">0h</option> <option value="00:00:00">0h</option>
<option value="01:00:00">1h</option> <option value="01:00:00">1h</option>
<option value="02:00:00">2h</option> <option value="02:00:00">2h</option>
@@ -54,11 +46,7 @@
<option value="12:00:00">12h</option> <option value="12:00:00">12h</option>
</select> </select>
<label class="input-group-text" for="slotMaxTime">À</label> <label class="input-group-text" for="slotMaxTime">À</label>
<select <select v-model="slotMaxTime" id="slotMaxTime" class="form-select">
v-model="slotMaxTime"
id="slotMaxTime"
class="form-select"
>
<option value="12:00:00">12h</option> <option value="12:00:00">12h</option>
<option value="13:00:00">13h</option> <option value="13:00:00">13h</option>
<option value="14:00:00">14h</option> <option value="14:00:00">14h</option>
@@ -86,9 +74,7 @@
v-model="showWeekends" v-model="showWeekends"
/> />
</span> </span>
<label <label for="showHideWE" class="form-check-label input-group-text"
for="showHideWE"
class="form-check-label input-group-text"
>Week-ends</label >Week-ends</label
> >
</div> </div>
@@ -98,16 +84,12 @@
<FullCalendar :options="calendarOptions" ref="calendarRef"> <FullCalendar :options="calendarOptions" ref="calendarRef">
<template v-slot:eventContent="{ event }: { event: EventApi }"> <template v-slot:eventContent="{ event }: { event: EventApi }">
<span :class="eventClasses"> <span :class="eventClasses">
<b v-if="event.extendedProps.is === 'remote'">{{ <b v-if="event.extendedProps.is === 'remote'">{{ event.title }}</b>
event.title
}}</b>
<b v-else-if="event.extendedProps.is === 'range'" <b v-else-if="event.extendedProps.is === 'range'"
>{{ formatDate(event.startStr) }} - >{{ formatDate(event.startStr) }} -
{{ event.extendedProps.locationName }}</b {{ event.extendedProps.locationName }}</b
> >
<b v-else-if="event.extendedProps.is === 'local'">{{ <b v-else-if="event.extendedProps.is === 'local'">{{ event.title }}</b>
event.title
}}</b>
<b v-else>no 'is'</b> <b v-else>no 'is'</b>
<a <a
v-if="event.extendedProps.is === 'range'" v-if="event.extendedProps.is === 'range'"
@@ -126,11 +108,7 @@
<h6 class="chill-red">{{ $t("copy_range_from_to") }}</h6> <h6 class="chill-red">{{ $t("copy_range_from_to") }}</h6>
</div> </div>
<div class="col-xs-12 col-sm-9 col-md-2"> <div class="col-xs-12 col-sm-9 col-md-2">
<select <select v-model="dayOrWeek" id="dayOrWeek" class="form-select">
v-model="dayOrWeek"
id="dayOrWeek"
class="form-select"
>
<option value="day">{{ $t("from_day_to_day") }}</option> <option value="day">{{ $t("from_day_to_day") }}</option>
<option value="week"> <option value="week">
{{ $t("from_week_to_week") }} {{ $t("from_week_to_week") }}
@@ -139,27 +117,16 @@
</div> </div>
<template v-if="dayOrWeek === 'day'"> <template v-if="dayOrWeek === 'day'">
<div class="col-xs-12 col-sm-3 col-md-3"> <div class="col-xs-12 col-sm-3 col-md-3">
<input <input class="form-control" type="date" v-model="copyFrom" />
class="form-control"
type="date"
v-model="copyFrom"
/>
</div> </div>
<div class="col-xs-12 col-sm-1 col-md-1 copy-chevron"> <div class="col-xs-12 col-sm-1 col-md-1 copy-chevron">
<i class="fa fa-angle-double-right"></i> <i class="fa fa-angle-double-right"></i>
</div> </div>
<div class="col-xs-12 col-sm-3 col-md-3"> <div class="col-xs-12 col-sm-3 col-md-3">
<input <input class="form-control" type="date" v-model="copyTo" />
class="form-control"
type="date"
v-model="copyTo"
/>
</div> </div>
<div class="col-xs-12 col-sm-5 col-md-1"> <div class="col-xs-12 col-sm-5 col-md-1">
<button <button class="btn btn-action float-end" @click="copyDay">
class="btn btn-action float-end"
@click="copyDay"
>
{{ $t("copy_range") }} {{ $t("copy_range") }}
</button> </button>
</div> </div>
@@ -171,11 +138,7 @@
id="copyFromWeek" id="copyFromWeek"
class="form-select" class="form-select"
> >
<option <option v-for="w in lastWeeks" :value="w.value" :key="w.value">
v-for="w in lastWeeks"
:value="w.value"
:key="w.value"
>
{{ w.text }} {{ w.text }}
</option> </option>
</select> </select>
@@ -184,25 +147,14 @@
<i class="fa fa-angle-double-right"></i> <i class="fa fa-angle-double-right"></i>
</div> </div>
<div class="col-xs-12 col-sm-3 col-md-3"> <div class="col-xs-12 col-sm-3 col-md-3">
<select <select v-model="copyToWeek" id="copyToWeek" class="form-select">
v-model="copyToWeek" <option v-for="w in nextWeeks" :value="w.value" :key="w.value">
id="copyToWeek"
class="form-select"
>
<option
v-for="w in nextWeeks"
:value="w.value"
:key="w.value"
>
{{ w.text }} {{ w.text }}
</option> </option>
</select> </select>
</div> </div>
<div class="col-xs-12 col-sm-5 col-md-1"> <div class="col-xs-12 col-sm-5 col-md-1">
<button <button class="btn btn-action float-end" @click="copyWeek">
class="btn btn-action float-end"
@click="copyWeek"
>
{{ $t("copy_range") }} {{ $t("copy_range") }}
</button> </button>
</div> </div>

View File

@@ -41,9 +41,7 @@ const futureStore = function (): Promise<Store<State>> {
}); });
store.commit("me/setWhoAmi", user, { root: true }); store.commit("me/setWhoAmi", user, { root: true });
store store.dispatch("locations/getLocations", null, { root: true }).then((_) => {
.dispatch("locations/getLocations", null, { root: true })
.then((_) => {
return store.dispatch("locations/getCurrentLocation", null, { return store.dispatch("locations/getCurrentLocation", null, {
root: true, root: true,
}); });

View File

@@ -29,10 +29,7 @@ export default {
(state: CalendarLocalsState) => (state: CalendarLocalsState) =>
({ start, end }: { start: Date; end: Date }): boolean => { ({ start, end }: { start: Date; end: Date }): boolean => {
for (const range of state.localsLoaded) { for (const range of state.localsLoaded) {
if ( if (start.getTime() === range.start && end.getTime() === range.end) {
start.getTime() === range.start &&
end.getTime() === range.end
) {
return true; return true;
} }
} }
@@ -54,10 +51,7 @@ export default {
}); });
state.key = state.key + toAdd.length; state.key = state.key + toAdd.length;
}, },
addLoaded( addLoaded(state: CalendarLocalsState, payload: { start: Date; end: Date }) {
state: CalendarLocalsState,
payload: { start: Date; end: Date },
) {
state.localsLoaded.push({ state.localsLoaded.push({
start: payload.start.getTime(), start: payload.start.getTime(),
end: payload.end.getTime(), end: payload.end.getTime(),
@@ -85,11 +79,7 @@ export default {
end: end, end: end,
}); });
return fetchCalendarLocalForUser( return fetchCalendarLocalForUser(ctx.rootGetters["me/getMe"], start, end)
ctx.rootGetters["me/getMe"],
start,
end,
)
.then((remotes: CalendarLight[]) => { .then((remotes: CalendarLight[]) => {
// to be add when reactivity problem will be solve ? // to be add when reactivity problem will be solve ?
//ctx.commit('addRemotes', remotes); //ctx.commit('addRemotes', remotes);

View File

@@ -40,10 +40,7 @@ export default {
(state: CalendarRangesState) => (state: CalendarRangesState) =>
({ start, end }: { start: Date; end: Date }): boolean => { ({ start, end }: { start: Date; end: Date }): boolean => {
for (const range of state.rangesLoaded) { for (const range of state.rangesLoaded) {
if ( if (start.getTime() === range.start && end.getTime() === range.end) {
start.getTime() === range.start &&
end.getTime() === range.end
) {
return true; return true;
} }
} }
@@ -110,9 +107,7 @@ export default {
state: CalendarRangesState, state: CalendarRangesState,
externalEvents: (EventInput & { id: string })[], externalEvents: (EventInput & { id: string })[],
) { ) {
const toAdd = externalEvents.filter( const toAdd = externalEvents.filter((r) => !state.rangesIndex.has(r.id));
(r) => !state.rangesIndex.has(r.id),
);
toAdd.forEach((r) => { toAdd.forEach((r) => {
state.rangesIndex.add(r.id); state.rangesIndex.add(r.id);
@@ -120,10 +115,7 @@ export default {
}); });
state.key = state.key + toAdd.length; state.key = state.key + toAdd.length;
}, },
addLoaded( addLoaded(state: CalendarRangesState, payload: { start: Date; end: Date }) {
state: CalendarRangesState,
payload: { start: Date; end: Date },
) {
state.rangesLoaded.push({ state.rangesLoaded.push({
start: payload.start.getTime(), start: payload.start.getTime(),
end: payload.end.getTime(), end: payload.end.getTime(),
@@ -142,17 +134,12 @@ export default {
}, },
removeRange(state: CalendarRangesState, calendarRangeId: number) { removeRange(state: CalendarRangesState, calendarRangeId: number) {
const found = state.ranges.find( const found = state.ranges.find(
(r) => (r) => r.calendarRangeId === calendarRangeId && r.is === "range",
r.calendarRangeId === calendarRangeId && r.is === "range",
); );
if (found !== undefined) { if (found !== undefined) {
state.ranges = state.ranges.filter( state.ranges = state.ranges.filter(
(r) => (r) => !(r.calendarRangeId === calendarRangeId && r.is === "range"),
!(
r.calendarRangeId === calendarRangeId &&
r.is === "range"
),
); );
if (typeof found.id === "string") { if (typeof found.id === "string") {
@@ -211,11 +198,7 @@ export default {
}, },
createRange( createRange(
ctx: Context, ctx: Context,
{ { start, end, location }: { start: Date; end: Date; location: Location },
start,
end,
location,
}: { start: Date; end: Date; location: Location },
): Promise<null> { ): Promise<null> {
const url = `/api/1.0/calendar/calendar-range.json?`; const url = `/api/1.0/calendar/calendar-range.json?`;
@@ -240,11 +223,7 @@ export default {
}, },
} as CalendarRangeCreate; } as CalendarRangeCreate;
return makeFetch<CalendarRangeCreate, CalendarRange>( return makeFetch<CalendarRangeCreate, CalendarRange>("POST", url, body)
"POST",
url,
body,
)
.then((newRange) => { .then((newRange) => {
ctx.commit("addRange", newRange); ctx.commit("addRange", newRange);
@@ -281,11 +260,7 @@ export default {
}, },
} as CalendarRangeEdit; } as CalendarRangeEdit;
return makeFetch<CalendarRangeEdit, CalendarRange>( return makeFetch<CalendarRangeEdit, CalendarRange>("PATCH", url, body)
"PATCH",
url,
body,
)
.then((range) => { .then((range) => {
ctx.commit("updateRange", range); ctx.commit("updateRange", range);
return Promise.resolve(null); return Promise.resolve(null);
@@ -310,11 +285,7 @@ export default {
}, },
} as CalendarRangeEdit; } as CalendarRangeEdit;
return makeFetch<CalendarRangeEdit, CalendarRange>( return makeFetch<CalendarRangeEdit, CalendarRange>("PATCH", url, body)
"PATCH",
url,
body,
)
.then((range) => { .then((range) => {
ctx.commit("updateRange", range); ctx.commit("updateRange", range);
return Promise.resolve(null); return Promise.resolve(null);
@@ -334,20 +305,14 @@ export default {
for (const r of rangesToCopy) { for (const r of rangesToCopy) {
const start = new Date(ISOToDatetime(r.start) as Date); const start = new Date(ISOToDatetime(r.start) as Date);
start.setFullYear( start.setFullYear(to.getFullYear(), to.getMonth(), to.getDate());
to.getFullYear(),
to.getMonth(),
to.getDate(),
);
const end = new Date(ISOToDatetime(r.end) as Date); const end = new Date(ISOToDatetime(r.end) as Date);
end.setFullYear(to.getFullYear(), to.getMonth(), to.getDate()); end.setFullYear(to.getFullYear(), to.getMonth(), to.getDate());
const location = ctx.rootGetters["locations/getLocationById"]( const location = ctx.rootGetters["locations/getLocationById"](
r.locationId, r.locationId,
); );
promises.push( promises.push(ctx.dispatch("createRange", { start, end, location }));
ctx.dispatch("createRange", { start, end, location }),
);
} }
return Promise.all(promises).then(() => Promise.resolve(null)); return Promise.all(promises).then(() => Promise.resolve(null));
@@ -369,9 +334,7 @@ export default {
r.locationId, r.locationId,
); );
promises.push( promises.push(ctx.dispatch("createRange", { start, end, location }));
ctx.dispatch("createRange", { start, end, location }),
);
} }
return Promise.all(promises).then(() => Promise.resolve(null)); return Promise.all(promises).then(() => Promise.resolve(null));

View File

@@ -29,10 +29,7 @@ export default {
(state: CalendarRemotesState) => (state: CalendarRemotesState) =>
({ start, end }: { start: Date; end: Date }): boolean => { ({ start, end }: { start: Date; end: Date }): boolean => {
for (const range of state.remotesLoaded) { for (const range of state.remotesLoaded) {
if ( if (start.getTime() === range.start && end.getTime() === range.end) {
start.getTime() === range.start &&
end.getTime() === range.end
) {
return true; return true;
} }
} }
@@ -85,11 +82,7 @@ export default {
end: end, end: end,
}); });
return fetchCalendarRemoteForUser( return fetchCalendarRemoteForUser(ctx.rootGetters["me/getMe"], start, end)
ctx.rootGetters["me/getMe"],
start,
end,
)
.then((remotes: CalendarRemote[]) => { .then((remotes: CalendarRemote[]) => {
// to be add when reactivity problem will be solve ? // to be add when reactivity problem will be solve ?
//ctx.commit('addRemotes', remotes); //ctx.commit('addRemotes', remotes);

View File

@@ -112,11 +112,8 @@ export default {
results.forEach((i) => { results.forEach((i) => {
if (!users.some((j) => i.user.id === j.id)) { if (!users.some((j) => i.user.id === j.id)) {
let ratio = Math.floor( let ratio = Math.floor(users.length / COLORS.length);
users.length / COLORS.length, let colorIndex = users.length - ratio * COLORS.length;
);
let colorIndex =
users.length - ratio * COLORS.length;
users.push({ users.push({
id: i.user.id, id: i.user.id,
username: i.user.username, username: i.user.username,
@@ -153,45 +150,29 @@ export default {
(me) => (me) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
this.users.logged = me; this.users.logged = me;
let currentUser = users.find( let currentUser = users.find((u) => u.id === me.id);
(u) => u.id === me.id,
);
this.value = currentUser; this.value = currentUser;
fetchCalendar(currentUser.id).then( fetchCalendar(currentUser.id).then(
(calendar) => (calendar) =>
new Promise( new Promise((resolve, reject) => {
(resolve, reject) => { let results = calendar.results;
let results = let events = results.map((i) => ({
calendar.results; start: i.startDate.datetime,
let events = end: i.endDate.datetime,
results.map( }));
(i) => ({ let calendarEventsCurrentUser = {
start: i
.startDate
.datetime,
end: i
.endDate
.datetime,
}),
);
let calendarEventsCurrentUser =
{
events: events, events: events,
color: "darkblue", color: "darkblue",
id: 1000, id: 1000,
editable: false, editable: false,
}; };
this.calendarEvents.user = this.calendarEvents.user = calendarEventsCurrentUser;
calendarEventsCurrentUser;
this.selectUsers( this.selectUsers(currentUser);
currentUser,
);
resolve(); resolve();
}, }),
),
); );
resolve(); resolve();
@@ -209,9 +190,7 @@ export default {
return `${value.username}`; return `${value.username}`;
}, },
coloriseSelectedValues() { coloriseSelectedValues() {
let tags = document.querySelectorAll( let tags = document.querySelectorAll("div.multiselect__tags-wrap")[0];
"div.multiselect__tags-wrap",
)[0];
if (tags.hasChildNodes()) { if (tags.hasChildNodes()) {
let children = tags.childNodes; let children = tags.childNodes;
@@ -232,8 +211,8 @@ export default {
}, },
selectEvents() { selectEvents() {
let selectedUsersId = this.users.selected.map((a) => a.id); let selectedUsersId = this.users.selected.map((a) => a.id);
this.calendarEvents.selected = this.calendarEvents.loaded.filter( this.calendarEvents.selected = this.calendarEvents.loaded.filter((a) =>
(a) => selectedUsersId.includes(a.id), selectedUsersId.includes(a.id),
); );
}, },
selectUsers(value) { selectUsers(value) {
@@ -243,9 +222,7 @@ export default {
this.updateEventsSource(); this.updateEventsSource();
}, },
unSelectUsers(value) { unSelectUsers(value) {
this.users.selected = this.users.selected.filter( this.users.selected = this.users.selected.filter((a) => a.id != value.id);
(a) => a.id != value.id,
);
this.selectEvents(); this.selectEvents();
this.updateEventsSource(); this.updateEventsSource();
}, },

View File

@@ -20,10 +20,7 @@
</option> </option>
<template v-for="t in templates" :key="t.id"> <template v-for="t in templates" :key="t.id">
<option :value="t.id"> <option :value="t.id">
{{ {{ localizeString(t.name) || "Aucun nom défini" }}
localizeString(t.name) ||
"Aucun nom défini"
}}
</option> </option>
</template> </template>
</select> </select>
@@ -31,9 +28,7 @@
v-if="canGenerate" v-if="canGenerate"
class="btn btn-update btn-sm change-icon" class="btn btn-update btn-sm change-icon"
:href="buildUrlGenerate" :href="buildUrlGenerate"
@click.prevent=" @click.prevent="clickGenerate($event, buildUrlGenerate)"
clickGenerate($event, buildUrlGenerate)
"
><i class="fa fa-fw fa-cog" ><i class="fa fa-fw fa-cog"
/></a> /></a>
<a <a

View File

@@ -13,8 +13,9 @@ const startApp = (
const inputTitle = collectionEntry?.querySelector("input[type='text']"); const inputTitle = collectionEntry?.querySelector("input[type='text']");
const input_stored_object: HTMLInputElement | null = const input_stored_object: HTMLInputElement | null = divElement.querySelector(
divElement.querySelector("input[data-stored-object]"); "input[data-stored-object]",
);
if (null === input_stored_object) { if (null === input_stored_object) {
throw new Error("input to stored object not found"); throw new Error("input to stored object not found");
} }
@@ -53,9 +54,7 @@ const startApp = (
console.log("version added", stored_object_version); console.log("version added", stored_object_version);
this.$data.existingDoc = stored_object; this.$data.existingDoc = stored_object;
this.$data.existingDoc.currentVersion = stored_object_version; this.$data.existingDoc.currentVersion = stored_object_version;
input_stored_object.value = JSON.stringify( input_stored_object.value = JSON.stringify(this.$data.existingDoc);
this.$data.existingDoc,
);
if (this.$data.inputTitle) { if (this.$data.inputTitle) {
if (!this.$data.inputTitle?.value) { if (!this.$data.inputTitle?.value) {
this.$data.inputTitle.value = file_name; this.$data.inputTitle.value = file_name;

View File

@@ -49,9 +49,7 @@
<li v-if="isHistoryViewable"> <li v-if="isHistoryViewable">
<history-button <history-button
:stored-object="props.storedObject" :stored-object="props.storedObject"
:can-edit=" :can-edit="canEdit && props.storedObject._permissions.canEdit"
canEdit && props.storedObject._permissions.canEdit
"
></history-button> ></history-button>
</li> </li>
</ul> </ul>
@@ -129,9 +127,7 @@ const props = withDefaults(defineProps<DocumentActionButtonsGroupConfig>(), {
canDownload: true, canDownload: true,
canConvertPdf: true, canConvertPdf: true,
returnPath: returnPath:
window.location.pathname + window.location.pathname + window.location.search + window.location.hash,
window.location.search +
window.location.hash,
}); });
/** /**

View File

@@ -29,9 +29,7 @@
</modal> </modal>
</teleport> </teleport>
<div class="col-12 m-auto sticky-top"> <div class="col-12 m-auto sticky-top">
<div <div class="row justify-content-center border-bottom pdf-tools d-md-none">
class="row justify-content-center border-bottom pdf-tools d-md-none"
>
<div class="col-5 text-center turn-page"> <div class="col-5 text-center turn-page">
<select <select
class="form-select form-select-sm" class="form-select form-select-sm"
@@ -92,10 +90,7 @@
v-if="signature.zones.length === 1 && signedState !== 'signed'" v-if="signature.zones.length === 1 && signedState !== 'signed'"
class="col-5 p-0 text-center turnSignature" class="col-5 p-0 text-center turnSignature"
> >
<button <button class="btn btn-light btn-sm" @click="goToSignatureZoneUnique">
class="btn btn-light btn-sm"
@click="goToSignatureZoneUnique"
>
{{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }} {{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
</button> </button>
</div> </div>
@@ -150,10 +145,7 @@
:title="trans(SIGNATURES_ADD_SIGN_ZONE)" :title="trans(SIGNATURES_ADD_SIGN_ZONE)"
> >
<template v-if="canvasEvent === 'add'"> <template v-if="canvasEvent === 'add'">
<div <div class="spinner-border spinner-border-sm" role="status">
class="spinner-border spinner-border-sm"
role="status"
>
<span class="visually-hidden">Loading...</span> <span class="visually-hidden">Loading...</span>
</div> </div>
</template> </template>
@@ -207,10 +199,7 @@
v-if="signature.zones.length === 1 && signedState !== 'signed'" v-if="signature.zones.length === 1 && signedState !== 'signed'"
class="col-4 d-xl-none text-center turnSignature p-0" class="col-4 d-xl-none text-center turnSignature p-0"
> >
<button <button class="btn btn-light btn-sm" @click="goToSignatureZoneUnique">
class="btn btn-light btn-sm"
@click="goToSignatureZoneUnique"
>
{{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }} {{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
</button> </button>
</div> </div>
@@ -238,10 +227,7 @@
v-if="signature.zones.length === 1 && signedState !== 'signed'" v-if="signature.zones.length === 1 && signedState !== 'signed'"
class="col-4 d-none d-xl-flex p-0 text-center turnSignature" class="col-4 d-none d-xl-flex p-0 text-center turnSignature"
> >
<button <button class="btn btn-light btn-sm" @click="goToSignatureZoneUnique">
class="btn btn-light btn-sm"
@click="goToSignatureZoneUnique"
>
{{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }} {{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
</button> </button>
</div> </div>
@@ -299,10 +285,7 @@
</template> </template>
<template v-else> <template v-else>
{{ trans(SIGNATURES_CLICK_ON_DOCUMENT) }} {{ trans(SIGNATURES_CLICK_ON_DOCUMENT) }}
<div <div class="spinner-border spinner-border-sm" role="status">
class="spinner-border spinner-border-sm"
role="status"
>
<span class="visually-hidden">Loading...</span> <span class="visually-hidden">Loading...</span>
</div> </div>
</template> </template>
@@ -562,14 +545,8 @@ const addCanvasEvents = () => {
); );
}); });
} else { } else {
const canvas = document.querySelectorAll( const canvas = document.querySelectorAll("canvas")[0] as HTMLCanvasElement;
"canvas", canvas.addEventListener("pointerup", (e) => canvasClick(e, canvas), false);
)[0] as HTMLCanvasElement;
canvas.addEventListener(
"pointerup",
(e) => canvasClick(e, canvas),
false,
);
} }
}; };
@@ -605,11 +582,7 @@ const hitSignature = (
scaleYToCanvas(zone.y, canvas.height, zone.PDFPage.height) < scaleYToCanvas(zone.y, canvas.height, zone.PDFPage.height) <
xy[1] && xy[1] &&
xy[1] < xy[1] <
scaleYToCanvas( scaleYToCanvas(zone.height - zone.y, canvas.height, zone.PDFPage.height) +
zone.height - zone.y,
canvas.height,
zone.PDFPage.height,
) +
zone.PDFPage.height * zoom.value; zone.PDFPage.height * zoom.value;
const selectZone = async (z: SignatureZone, canvas: HTMLCanvasElement) => { const selectZone = async (z: SignatureZone, canvas: HTMLCanvasElement) => {
@@ -625,8 +598,7 @@ const selectZoneEvent = (e: PointerEvent, canvas: HTMLCanvasElement) =>
signature.zones signature.zones
.filter( .filter(
(z) => (z) =>
(z.PDFPage.index + 1 === getCanvasId(canvas) && (z.PDFPage.index + 1 === getCanvasId(canvas) && multiPage.value) ||
multiPage.value) ||
(z.PDFPage.index + 1 === page.value && !multiPage.value), (z.PDFPage.index + 1 === page.value && !multiPage.value),
) )
.map((z) => { .map((z) => {

View File

@@ -153,12 +153,10 @@ const handleFile = async (file: File): Promise<void> => {
</p> </p>
<!-- todo i18n --> <!-- todo i18n -->
<p v-if="has_existing_doc"> <p v-if="has_existing_doc">
Déposez un document ou cliquez ici pour remplacer le document Déposez un document ou cliquez ici pour remplacer le document existant
existant
</p> </p>
<p v-else> <p v-else>
Déposez un document ou cliquez ici pour ouvrir le navigateur de Déposez un document ou cliquez ici pour ouvrir le navigateur de fichier
fichier
</p> </p>
</div> </div>
<div v-else class="waiting"> <div v-else class="waiting">

View File

@@ -35,9 +35,7 @@ async function download_and_open(event: Event): Promise<void> {
if (null === state.content) { if (null === state.content) {
event.preventDefault(); event.preventDefault();
const raw = await download_doc( const raw = await download_doc(build_convert_link(props.storedObject.uuid));
build_convert_link(props.storedObject.uuid),
);
state.content = window.URL.createObjectURL(raw); state.content = window.URL.createObjectURL(raw);
button.href = window.URL.createObjectURL(raw); button.href = window.URL.createObjectURL(raw);

View File

@@ -42,9 +42,7 @@ const editionUntilFormatted = computed<string>(() => {
<modal v-if="state.modalOpened" @close="state.modalOpened = false"> <modal v-if="state.modalOpened" @close="state.modalOpened = false">
<template v-slot:body> <template v-slot:body>
<div class="desktop-edit"> <div class="desktop-edit">
<p class="center"> <p class="center">Veuillez enregistrer vos modifications avant le</p>
Veuillez enregistrer vos modifications avant le
</p>
<p> <p>
<strong>{{ editionUntilFormatted }}</strong> <strong>{{ editionUntilFormatted }}</strong>
</p> </p>
@@ -57,23 +55,21 @@ const editionUntilFormatted = computed<string>(() => {
<p> <p>
<small <small
>Le document peut être édité uniquement en utilisant >Le document peut être édité uniquement en utilisant Libre
Libre Office.</small Office.</small
> >
</p> </p>
<p> <p>
<small <small
>En cas d'échec lors de l'enregistrement, sauver le >En cas d'échec lors de l'enregistrement, sauver le document sur
document sur le poste de travail avant de le déposer le poste de travail avant de le déposer à nouveau ici.</small
à nouveau ici.</small
> >
</p> </p>
<p> <p>
<small <small
>Vous pouvez naviguez sur d'autres pages pendant >Vous pouvez naviguez sur d'autres pages pendant l'édition.</small
l'édition.</small
> >
</p> </p>
</div> </div>

View File

@@ -95,10 +95,7 @@ async function download_and_open(): Promise<void> {
let raw; let raw;
try { try {
raw = await download_and_decrypt_doc( raw = await download_and_decrypt_doc(props.storedObject, props.atVersion);
props.storedObject,
props.atVersion,
);
} catch (e) { } catch (e) {
console.error("error while downloading and decrypting document"); console.error("error while downloading and decrypting document");
console.error(e); console.error(e);

View File

@@ -49,8 +49,7 @@ const isRestored = computed<boolean>(
); );
const isDuplicated = computed<boolean>( const isDuplicated = computed<boolean>(
() => () => props.version.version === 0 && null !== props.version["from-restored"],
props.version.version === 0 && null !== props.version["from-restored"],
); );
const classes = computed<{ const classes = computed<{
@@ -70,16 +69,9 @@ const classes = computed<{
<div :class="classes"> <div :class="classes">
<div <div
class="col-12 tags" class="col-12 tags"
v-if=" v-if="isCurrent || isKeptBeforeConversion || isRestored || isDuplicated"
isCurrent ||
isKeptBeforeConversion ||
isRestored ||
isDuplicated
"
>
<span class="badge bg-success" v-if="isCurrent"
>Version actuelle</span
> >
<span class="badge bg-success" v-if="isCurrent">Version actuelle</span>
<span class="badge bg-info" v-if="isKeptBeforeConversion" <span class="badge bg-info" v-if="isKeptBeforeConversion"
>Conservée avant conversion dans un autre format</span >Conservée avant conversion dans un autre format</span
> >
@@ -96,21 +88,17 @@ const classes = computed<{
<span <span
><strong>&nbsp;#{{ version.version + 1 }}&nbsp;</strong></span ><strong>&nbsp;#{{ version.version + 1 }}&nbsp;</strong></span
> >
<template <template v-if="version.createdBy !== null && version.createdAt !== null"
v-if="version.createdBy !== null && version.createdAt !== null"
><strong v-if="version.version == 0">créé par</strong ><strong v-if="version.version == 0">créé par</strong
><strong v-else>modifié par</strong> ><strong v-else>modifié par</strong>
<span class="badge-user" <span class="badge-user"
><UserRenderBoxBadge ><UserRenderBoxBadge :user="version.createdBy"></UserRenderBoxBadge
:user="version.createdBy"
></UserRenderBoxBadge
></span> ></span>
<strong>à</strong> <strong>à</strong>
{{ {{
$d(ISOToDatetime(version.createdAt.datetime8601), "long") $d(ISOToDatetime(version.createdAt.datetime8601), "long")
}}</template }}</template
><template ><template v-if="version.createdBy === null && version.createdAt !== null"
v-if="version.createdBy === null && version.createdAt !== null"
><strong v-if="version.version == 0">Créé le</strong ><strong v-if="version.version == 0">Créé le</strong
><strong v-else>modifié le</strong> ><strong v-else>modifié le</strong>
{{ {{

View File

@@ -2,9 +2,7 @@
<a <a
:class="Object.assign(props.classes, { btn: true })" :class="Object.assign(props.classes, { btn: true })"
@click="beforeLeave($event)" @click="beforeLeave($event)"
:href=" :href="build_wopi_editor_link(props.storedObject.uuid, props.returnPath)"
build_wopi_editor_link(props.storedObject.uuid, props.returnPath)
"
> >
<i class="fa fa-paragraph"></i> <i class="fa fa-paragraph"></i>
Editer en ligne Editer en ligne

View File

@@ -145,9 +145,7 @@ async function download_info_link(
function build_wopi_editor_link(uuid: string, returnPath?: string) { function build_wopi_editor_link(uuid: string, returnPath?: string) {
if (returnPath === undefined) { if (returnPath === undefined) {
returnPath = returnPath =
window.location.pathname + window.location.pathname + window.location.search + window.location.hash;
window.location.search +
window.location.hash;
} }
return ( return (
@@ -186,10 +184,7 @@ async function download_and_decrypt_doc(
) { ) {
downloadInfo = storedObject._links.downloadLink; downloadInfo = storedObject._links.downloadLink;
} else { } else {
downloadInfo = await download_info_link( downloadInfo = await download_info_link(storedObject, atVersionToDownload);
storedObject,
atVersionToDownload,
);
} }
const rawResponse = await window.fetch(downloadInfo.url); const rawResponse = await window.fetch(downloadInfo.url);
@@ -244,10 +239,7 @@ async function download_doc_as_pdf(storedObject: StoredObject): Promise<Blob> {
} }
if (storedObject.currentVersion?.type === "application/pdf") { if (storedObject.currentVersion?.type === "application/pdf") {
return download_and_decrypt_doc( return download_and_decrypt_doc(storedObject, storedObject.currentVersion);
storedObject,
storedObject.currentVersion,
);
} }
const convertLink = build_convert_link(storedObject.uuid); const convertLink = build_convert_link(storedObject.uuid);

View File

@@ -613,4 +613,14 @@ class User implements UserInterface, \Stringable, PasswordAuthenticatedUserInter
return $this; return $this;
} }
/**
* Check if the current object is an instance of User.
*
* @return bool returns true if the current object is an instance of User, false otherwise
*/
public function isUser(): bool
{
return true;
}
} }

View File

@@ -27,6 +27,8 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\Translation\TranslatableInterface; use Symfony\Contracts\Translation\TranslatableInterface;
use Symfony\Contracts\Translation\TranslatorInterface; use Symfony\Contracts\Translation\TranslatorInterface;
// command to get the report with curl : curl --user "center a_social:password" "http://localhost:8000/fr/exports/generate/count_person?export[filters][person_gender_filter][enabled]=&export[filters][person_nationality_filter][enabled]=&export[filters][person_nationality_filter][form][nationalities]=&export[aggregators][person_nationality_aggregator][order]=1&export[aggregators][person_nationality_aggregator][form][group_by_level]=country&export[submit]=&export[_token]=RHpjHl389GrK-bd6iY5NsEqrD5UKOTHH40QKE9J1edU" --globoff
/** /**
* Create a CSV List for the export. * Create a CSV List for the export.
*/ */

View File

@@ -76,6 +76,24 @@ final class PhonenumberHelper implements PhoneNumberHelperInterface
->formatOutOfCountryCallingNumber($phoneNumber, $this->config['default_carrier_code']); ->formatOutOfCountryCallingNumber($phoneNumber, $this->config['default_carrier_code']);
} }
/**
* @throws NumberParseException
*/
public function parse(string $phoneNumber): PhoneNumber
{
$sanitizedPhoneNumber = $phoneNumber;
if (str_starts_with($sanitizedPhoneNumber, '00')) {
$sanitizedPhoneNumber = '+'.substr($sanitizedPhoneNumber, 2, null);
}
if (!str_starts_with($sanitizedPhoneNumber, '+') && !str_starts_with($sanitizedPhoneNumber, '0')) {
$sanitizedPhoneNumber = '+'.$sanitizedPhoneNumber;
}
return $this->phoneNumberUtil->parse($sanitizedPhoneNumber, $this->config['default_carrier_code']);
}
/** /**
* Get type (mobile, landline, ...) for phone number. * Get type (mobile, landline, ...) for phone number.
*/ */

View File

@@ -56,9 +56,7 @@ export const ISOToDatetime = (str: string | null): Date | null => {
[time, timezone] = times.split(times.charAt(8)), [time, timezone] = times.split(times.charAt(8)),
[hours, minutes, seconds] = time.split(":").map((s) => parseInt(s)); [hours, minutes, seconds] = time.split(":").map((s) => parseInt(s));
if ("0000" === timezone) { if ("0000" === timezone) {
return new Date( return new Date(Date.UTC(year, month - 1, date, hours, minutes, seconds));
Date.UTC(year, month - 1, date, hours, minutes, seconds),
);
} }
return new Date(year, month - 1, date, hours, minutes, seconds); return new Date(year, month - 1, date, hours, minutes, seconds);
@@ -154,9 +152,7 @@ export const intervalISOToDays = (str: string | null): number | null => {
vstring = ""; vstring = "";
break; break;
default: default:
throw Error( throw Error("this character should not appears: " + str.charAt(i));
"this character should not appears: " + str.charAt(i),
);
} }
} }

View File

@@ -126,7 +126,8 @@ function loadDynamicPicker(element) {
-1 === -1 ===
this.suggested.findIndex( this.suggested.findIndex(
(e) => e.type === entity.type && e.id === entity.id, (e) => e.type === entity.type && e.id === entity.id,
) ) &&
"me" !== entity
) { ) {
this.suggested.push(entity); this.suggested.push(entity);
} }

View File

@@ -11,6 +11,11 @@ export interface Civility {
// TODO // TODO
} }
export interface Household {
type: "household";
id: number;
}
export interface Job { export interface Job {
id: number; id: number;
type: "user_job"; type: "user_job";
@@ -215,3 +220,61 @@ export interface ExportGeneration {
export interface PrivateCommentEmbeddable { export interface PrivateCommentEmbeddable {
comments: Record<number, string>; comments: Record<number, string>;
} }
// API Exception types
export interface TransportExceptionInterface {
name: string;
}
export interface ValidationExceptionInterface
extends TransportExceptionInterface {
name: "ValidationException";
error: object;
violations: string[];
titles: string[];
propertyPaths: string[];
}
export interface AccessExceptionInterface extends TransportExceptionInterface {
name: "AccessException";
violations: string[];
}
export interface NotFoundExceptionInterface
extends TransportExceptionInterface {
name: "NotFoundException";
}
export interface ServerExceptionInterface extends TransportExceptionInterface {
name: "ServerException";
message: string;
code: number;
body: string;
}
export interface ConflictHttpExceptionInterface
extends TransportExceptionInterface {
name: "ConflictHttpException";
violations: string[];
}
export type ApiException =
| ValidationExceptionInterface
| AccessExceptionInterface
| NotFoundExceptionInterface
| ServerExceptionInterface
| ConflictHttpExceptionInterface;
export interface Modal {
showModal: boolean;
modalDialogClass: string;
}
export interface Selected {
result: UserGroupOrUser;
}
export interface addNewEntities {
selected: Selected[];
modal: Modal;
}

View File

@@ -144,10 +144,7 @@
</template> </template>
<template #action> <template #action>
<li v-if="!this.context.edit && this.useDatePane"> <li v-if="!this.context.edit && this.useDatePane">
<button <button class="btn btn-update change-icon" @click="closeEditPane">
class="btn btn-update change-icon"
@click="closeEditPane"
>
{{ $t("nav.next") }} {{ $t("nav.next") }}
<i class="fa fa-fw fa-arrow-right" /> <i class="fa fa-fw fa-arrow-right" />
</button> </button>
@@ -370,8 +367,7 @@ export default {
getTextTitle() { getTextTitle() {
if ( if (
typeof this.options.title !== "undefined" && typeof this.options.title !== "undefined" &&
(this.options.title.edit !== null || (this.options.title.edit !== null || this.options.title.create !== null)
this.options.title.create !== null)
) { ) {
return this.context.edit return this.context.edit
? this.options.title.edit ? this.options.title.edit
@@ -489,10 +485,7 @@ export default {
if (!this.context.edit) { if (!this.context.edit) {
this.context.edit = true; this.context.edit = true;
this.context.addressId = params.addressId; this.context.addressId = params.addressId;
console.log( console.log("context is now edit, with address", params.addressId);
"context is now edit, with address",
params.addressId,
);
} }
} }
}, },
@@ -619,9 +612,7 @@ export default {
? this.entity.address.confidential ? this.entity.address.confidential
: false; : false;
this.entity.selected.isNoAddress = this.entity.selected.isNoAddress =
this.context.edit && this.entity.address.text === "" this.context.edit && this.entity.address.text === "" ? true : false;
? true
: false;
this.entity.selected.country = this.context.edit this.entity.selected.country = this.context.edit
? this.entity.address.country ? this.entity.address.country
@@ -716,8 +707,7 @@ export default {
// add the address reference, if any // add the address reference, if any
if (this.entity.selected.address.addressReference !== undefined) { if (this.entity.selected.address.addressReference !== undefined) {
newAddress = Object.assign(newAddress, { newAddress = Object.assign(newAddress, {
addressReference: addressReference: this.entity.selected.address.addressReference,
this.entity.selected.address.addressReference,
}); });
} else { } else {
newAddress = Object.assign(newAddress, { newAddress = Object.assign(newAddress, {
@@ -737,10 +727,7 @@ export default {
}); });
} }
if (this.validTo && null !== this.entity.selected.valid.to) { if (this.validTo && null !== this.entity.selected.valid.to) {
console.log( console.log("add validTo in fetch body", this.entity.selected.valid.to);
"add validTo in fetch body",
this.entity.selected.valid.to,
);
newAddress = Object.assign(newAddress, { newAddress = Object.assign(newAddress, {
validTo: { validTo: {
datetime: `${this.entity.selected.valid.to.toISOString().split("T")[0]}T00:00:00+0100`, datetime: `${this.entity.selected.valid.to.toISOString().split("T")[0]}T00:00:00+0100`,
@@ -752,10 +739,7 @@ export default {
newPostcode = Object.assign(newPostcode, { newPostcode = Object.assign(newPostcode, {
country: { id: this.entity.selected.country.id }, country: { id: this.entity.selected.country.id },
}); //TODO why not assign postcodeBody here = Object.assign(postcodeBody, {'origin': 3}); ? }); //TODO why not assign postcodeBody here = Object.assign(postcodeBody, {'origin': 3}); ?
console.log( console.log("writeNew postcode is true! newPostcode: ", newPostcode);
"writeNew postcode is true! newPostcode: ",
newPostcode,
);
newAddress = Object.assign(newAddress, { newAddress = Object.assign(newAddress, {
newPostcode: newPostcode, newPostcode: newPostcode,
}); });

View File

@@ -72,10 +72,7 @@ export default {
this.entity.addressMap.zoom, this.entity.addressMap.zoom,
); );
} else { } else {
this.map.setView( this.map.setView(lonLatForLeaflet(this.addressPoint.coordinates), 15);
lonLatForLeaflet(this.addressPoint.coordinates),
15,
);
} }
this.map.scrollWheelZoom.disable(); this.map.scrollWheelZoom.disable();
@@ -105,9 +102,7 @@ export default {
}, },
update() { update() {
if (this.marker && this.entity.addressMap.center) { if (this.marker && this.entity.addressMap.center) {
this.marker.setLatLng( this.marker.setLatLng(lonLatForLeaflet(this.entity.addressMap.center));
lonLatForLeaflet(this.entity.addressMap.center),
);
this.map.panTo(lonLatForLeaflet(this.entity.addressMap.center)); this.map.panTo(lonLatForLeaflet(this.entity.addressMap.center));
} }
}, },

View File

@@ -76,9 +76,7 @@ export default {
props: ["entity", "context", "updateMapCenter", "flag", "checkErrors"], props: ["entity", "context", "updateMapCenter", "flag", "checkErrors"],
data() { data() {
return { return {
value: this.context.edit value: this.context.edit ? this.entity.address.addressReference : null,
? this.entity.address.addressReference
: null,
isLoading: false, isLoading: false,
}; };
}, },
@@ -151,8 +149,7 @@ export default {
.then( .then(
(addresses) => (addresses) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
this.entity.loaded.addresses = this.entity.loaded.addresses = addresses.results;
addresses.results;
this.isLoading = false; this.isLoading = false;
resolve(); resolve();
}), }),
@@ -169,8 +166,7 @@ export default {
.then( .then(
(addresses) => (addresses) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
this.entity.loaded.addresses = this.entity.loaded.addresses = addresses.results;
addresses.results;
this.isLoading = false; this.isLoading = false;
resolve(); resolve();
}), }),

View File

@@ -136,9 +136,7 @@ export default {
}, },
methods: { methods: {
transName(value) { transName(value) {
return value.code && value.name return value.code && value.name ? `${value.name} (${value.code})` : "";
? `${value.name} (${value.code})`
: "";
}, },
selectCity(value) { selectCity(value) {
console.log(value); console.log(value);
@@ -146,8 +144,7 @@ export default {
this.entity.selected.postcode.name = value.name; this.entity.selected.postcode.name = value.name;
this.entity.selected.postcode.code = value.code; this.entity.selected.postcode.code = value.code;
if (value.center) { if (value.center) {
this.entity.selected.postcode.coordinates = this.entity.selected.postcode.coordinates = value.center.coordinates;
value.center.coordinates;
} }
this.entity.selected.writeNew.postcode = false; this.entity.selected.writeNew.postcode = false;
this.$emit("getReferenceAddresses", value); this.$emit("getReferenceAddresses", value);
@@ -168,8 +165,7 @@ export default {
.then( .then(
(cities) => (cities) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
this.entity.loaded.cities = this.entity.loaded.cities = cities.results.filter(
cities.results.filter(
(c) => c.origin !== 3, (c) => c.origin !== 3,
); // filter out user-defined cities ); // filter out user-defined cities
this.isLoading = false; this.isLoading = false;
@@ -188,8 +184,7 @@ export default {
.then( .then(
(cities) => (cities) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
this.entity.loaded.cities = this.entity.loaded.cities = cities.results.filter(
cities.results.filter(
(c) => c.origin !== 3, (c) => c.origin !== 3,
); // filter out user-defined cities ); // filter out user-defined cities
this.isLoading = false; this.isLoading = false;

View File

@@ -42,12 +42,8 @@ export default {
sortedCountries() { sortedCountries() {
const countries = this.entity.loaded.countries; const countries = this.entity.loaded.countries;
let sortedCountries = []; let sortedCountries = [];
sortedCountries.push( sortedCountries.push(...countries.filter((c) => c.countryCode === "FR"));
...countries.filter((c) => c.countryCode === "FR"), sortedCountries.push(...countries.filter((c) => c.countryCode === "BE"));
);
sortedCountries.push(
...countries.filter((c) => c.countryCode === "BE"),
);
sortedCountries.push( sortedCountries.push(
...countries ...countries
.filter((c) => c.countryCode !== "FR") .filter((c) => c.countryCode !== "FR")

View File

@@ -1,9 +1,6 @@
<template> <template>
<div v-if="insideModal === false" class="loading"> <div v-if="insideModal === false" class="loading">
<i <i v-if="flag.loading" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw" />
v-if="flag.loading"
class="fa fa-circle-o-notch fa-spin fa-2x fa-fw"
/>
<span class="sr-only">{{ $t("loading") }}</span> <span class="sr-only">{{ $t("loading") }}</span>
</div> </div>
@@ -142,8 +139,7 @@ export default {
address["street"] = this.entity.selected.address.street address["street"] = this.entity.selected.address.street
? this.entity.selected.address.street ? this.entity.selected.address.street
: null; : null;
address["streetNumber"] = this.entity.selected.address address["streetNumber"] = this.entity.selected.address.streetNumber
.streetNumber
? this.entity.selected.address.streetNumber ? this.entity.selected.address.streetNumber
: null; : null;
address["floor"] = this.entity.selected.address.floor address["floor"] = this.entity.selected.address.floor
@@ -158,12 +154,10 @@ export default {
address["flat"] = this.entity.selected.address.flat address["flat"] = this.entity.selected.address.flat
? this.entity.selected.address.flat ? this.entity.selected.address.flat
: null; : null;
address["buildingName"] = this.entity.selected.address address["buildingName"] = this.entity.selected.address.buildingName
.buildingName
? this.entity.selected.address.buildingName ? this.entity.selected.address.buildingName
: null; : null;
address["distribution"] = this.entity.selected.address address["distribution"] = this.entity.selected.address.distribution
.distribution
? this.entity.selected.address.distribution ? this.entity.selected.address.distribution
: null; : null;
address["extra"] = this.entity.selected.address.extra address["extra"] = this.entity.selected.address.extra

View File

@@ -2,10 +2,7 @@
<div class="address-form"> <div class="address-form">
<!-- Not display in modal --> <!-- Not display in modal -->
<div v-if="insideModal === false" class="loading"> <div v-if="insideModal === false" class="loading">
<i <i v-if="flag.loading" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw" />
v-if="flag.loading"
class="fa fa-circle-o-notch fa-spin fa-2x fa-fw"
/>
<span class="sr-only">Loading...</span> <span class="sr-only">Loading...</span>
</div> </div>

View File

@@ -1,10 +1,7 @@
<template> <template>
<div v-if="!onlyButton" class="mt-4 flex-grow-1"> <div v-if="!onlyButton" class="mt-4 flex-grow-1">
<div class="loading"> <div class="loading">
<i <i v-if="flag.loading" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw" />
v-if="flag.loading"
class="fa fa-circle-o-notch fa-spin fa-2x fa-fw"
/>
<span class="sr-only">{{ $t("loading") }}</span> <span class="sr-only">{{ $t("loading") }}</span>
</div> </div>
@@ -45,9 +42,7 @@
name="button" name="button"
:title="$t(getTextButton)" :title="$t(getTextButton)"
> >
<span v-if="displayTextButton">{{ <span v-if="displayTextButton">{{ $t(getTextButton) }}</span>
$t(getTextButton)
}}</span>
</button> </button>
</template> </template>
</action-buttons> </action-buttons>
@@ -60,9 +55,7 @@
:use-date-pane="useDatePane" :use-date-pane="useDatePane"
/> />
<div <div v-if="this.context.target.name === 'household' || this.context.edit">
v-if="this.context.target.name === 'household' || this.context.edit"
>
<action-buttons :options="this.options" :defaultz="this.defaultz"> <action-buttons :options="this.options" :defaultz="this.defaultz">
<template #action> <template #action>
<button <button
@@ -73,9 +66,7 @@
name="button" name="button"
:title="$t(getTextButton)" :title="$t(getTextButton)"
> >
<span v-if="displayTextButton">{{ <span v-if="displayTextButton">{{ $t(getTextButton) }}</span>
$t(getTextButton)
}}</span>
</button> </button>
</template> </template>
</action-buttons> </action-buttons>
@@ -97,9 +88,7 @@
name="button" name="button"
:title="$t(getTextButton)" :title="$t(getTextButton)"
> >
<span v-if="displayTextButton">{{ <span v-if="displayTextButton">{{ $t(getTextButton) }}</span>
$t(getTextButton)
}}</span>
</button> </button>
</template> </template>
</action-buttons> </action-buttons>
@@ -165,9 +154,7 @@ export default {
: this.defaultz.button.text.create; : this.defaultz.button.text.create;
}, },
getSuccessText() { getSuccessText() {
return this.context.edit return this.context.edit ? "address_edit_success" : "address_new_success";
? "address_edit_success"
: "address_new_success";
}, },
onlyButton() { onlyButton() {
return typeof this.options.onlyButton !== "undefined" return typeof this.options.onlyButton !== "undefined"

View File

@@ -1,9 +1,6 @@
<template> <template>
<div v-if="insideModal === false" class="loading"> <div v-if="insideModal === false" class="loading">
<i <i v-if="flag.loading" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw" />
v-if="flag.loading"
class="fa fa-circle-o-notch fa-spin fa-2x fa-fw"
/>
<span class="sr-only">{{ $t("loading") }}</span> <span class="sr-only">{{ $t("loading") }}</span>
</div> </div>

View File

@@ -86,10 +86,7 @@ onMounted(() => {
<template> <template>
<div id="waiting-screen"> <div id="waiting-screen">
<div <div v-if="isPending && isFetching" class="alert alert-danger text-center">
v-if="isPending && isFetching"
class="alert alert-danger text-center"
>
<div> <div>
<p> <p>
{{ trans(EXPORT_GENERATION_EXPORT_GENERATION_IS_PENDING) }} {{ trans(EXPORT_GENERATION_EXPORT_GENERATION_IS_PENDING) }}

View File

@@ -67,9 +67,7 @@
@click="selectTab('MyWorkflows')" @click="selectTab('MyWorkflows')"
> >
{{ $t("my_workflows.tab") }} {{ $t("my_workflows.tab") }}
<tab-counter <tab-counter :count="state.workflows.count + state.workflowsCc.count" />
:count="state.workflows.count + state.workflowsCc.count"
/>
</a> </a>
</li> </li>
<li class="nav-item loading ms-auto py-2" v-if="loading"> <li class="nav-item loading ms-auto py-2" v-if="loading">

View File

@@ -25,11 +25,9 @@
</template> </template>
<template #body> <template #body>
<p class="news-date"> <p class="news-date">
<time <time class="createdBy" datetime="{{item.startDate.datetime}}">{{
class="createdBy" $d(newsItemStartDate(), "text")
datetime="{{item.startDate.datetime}}" }}</time>
>{{ $d(newsItemStartDate(), "text") }}</time
>
</p> </p>
<div v-html="convertMarkdownToHtml(item.content)"></div> <div v-html="convertMarkdownToHtml(item.content)"></div>
</template> </template>
@@ -93,10 +91,7 @@ const truncateContent = (content: string): string => {
// Truncate if amount of lines are too many // Truncate if amount of lines are too many
if (lines.length > props.maxLines && content.length < props.maxLength) { if (lines.length > props.maxLines && content.length < props.maxLength) {
const truncatedContent = lines const truncatedContent = lines.slice(0, props.maxLines).join("\n").trim();
.slice(0, props.maxLines)
.join("\n")
.trim();
return truncatedContent + "..."; return truncatedContent + "...";
} }
@@ -125,8 +120,7 @@ const truncateContent = (content: string): string => {
if (linkStartIndex !== -1) { if (linkStartIndex !== -1) {
const linkEndIndex = content.indexOf(")", linkStartIndex); const linkEndIndex = content.indexOf(")", linkStartIndex);
const url = content.slice(linkStartIndex + 1, linkEndIndex); const url = content.slice(linkStartIndex + 1, linkEndIndex);
truncatedContent = truncatedContent = truncatedContent.slice(0, linkStartIndex) + `(${url})`;
truncatedContent.slice(0, linkStartIndex) + `(${url})`;
} }
truncatedContent += "..."; truncatedContent += "...";

View File

@@ -20,10 +20,7 @@
<th scope="col" /> <th scope="col" />
</template> </template>
<template #tbody> <template #tbody>
<tr <tr v-for="(c, i) in accompanyingCourses.results" :key="`course-${i}`">
v-for="(c, i) in accompanyingCourses.results"
:key="`course-${i}`"
>
<td>{{ $d(c.openingDate.datetime, "short") }}</td> <td>{{ $d(c.openingDate.datetime, "short") }}</td>
<td> <td>
<span <span
@@ -37,11 +34,7 @@
</span> </span>
</td> </td>
<td> <td>
<span <span v-for="p in c.participations" class="me-1" :key="p.person.id">
v-for="p in c.participations"
class="me-1"
:key="p.person.id"
>
<on-the-fly <on-the-fly
:type="p.person.type" :type="p.person.type"
:id="p.person.id" :id="p.person.id"
@@ -52,16 +45,12 @@
</span> </span>
</td> </td>
<td> <td>
<span <span v-if="c.emergency" class="badge rounded-pill bg-danger me-1">{{
v-if="c.emergency" $t("emergency")
class="badge rounded-pill bg-danger me-1" }}</span>
>{{ $t("emergency") }}</span <span v-if="c.confidential" class="badge rounded-pill bg-danger">{{
> $t("confidential")
<span }}</span>
v-if="c.confidential"
class="badge rounded-pill bg-danger"
>{{ $t("confidential") }}</span
>
</td> </td>
<td> <td>
<a class="btn btn-sm btn-show" :href="getUrl(c)"> <a class="btn btn-sm btn-show" :href="getUrl(c)">

View File

@@ -27,9 +27,7 @@
:plural="counter.accompanyingCourses" :plural="counter.accompanyingCourses"
> >
<template #n> <template #n>
<span>{{ <span>{{ counter.accompanyingCourses }}</span>
counter.accompanyingCourses
}}</span>
</template> </template>
</i18n-t> </i18n-t>
</li> </li>

View File

@@ -20,10 +20,7 @@
<th scope="col" /> <th scope="col" />
</template> </template>
<template #tbody> <template #tbody>
<tr <tr v-for="(e, i) in evaluations.results" :key="`evaluation-${i}`">
v-for="(e, i) in evaluations.results"
:key="`evaluation-${i}`"
>
<td>{{ $d(e.maxDate.datetime, "short") }}</td> <td>{{ $d(e.maxDate.datetime, "short") }}</td>
<td> <td>
{{ localizeString(e.evaluation.title) }} {{ localizeString(e.evaluation.title) }}
@@ -31,10 +28,7 @@
<td> <td>
<span class="chill-entity entity-social-issue"> <span class="chill-entity entity-social-issue">
<span class="badge bg-chill-l-gray text-dark"> <span class="badge bg-chill-l-gray text-dark">
{{ {{ e.accompanyingPeriodWork.socialAction.issue.text }}
e.accompanyingPeriodWork.socialAction.issue
.text
}}
</span> </span>
</span> </span>
<h4 class="badge-title"> <h4 class="badge-title">
@@ -58,11 +52,7 @@
</span> </span>
</td> </td>
<td> <td>
<div <div class="btn-group-vertical" role="group" aria-label="Actions">
class="btn-group-vertical"
role="group"
aria-label="Actions"
>
<a class="btn btn-sm btn-show" :href="getUrl(e)"> <a class="btn btn-sm btn-show" :href="getUrl(e)">
{{ {{
$t("show_entity", { $t("show_entity", {
@@ -72,12 +62,7 @@
</a> </a>
<a <a
class="btn btn-sm btn-show" class="btn btn-sm btn-show"
:href=" :href="getUrl(e.accompanyingPeriodWork.accompanyingPeriod)"
getUrl(
e.accompanyingPeriodWork
.accompanyingPeriod,
)
"
> >
{{ {{
$t("show_entity", { $t("show_entity", {

View File

@@ -25,9 +25,7 @@
</td> </td>
<td v-else /> <td v-else />
<td> <td>
<span class="outdated">{{ <span class="outdated">{{ $d(t.endDate.datetime, "short") }}</span>
$d(t.endDate.datetime, "short")
}}</span>
</td> </td>
<td>{{ t.title }}</td> <td>{{ t.title }}</td>
<td> <td>
@@ -59,10 +57,7 @@
<th scope="col" /> <th scope="col" />
</template> </template>
<template #tbody> <template #tbody>
<tr <tr v-for="(t, i) in tasks.warning.results" :key="`task-warning-${i}`">
v-for="(t, i) in tasks.warning.results"
:key="`task-warning-${i}`"
>
<td> <td>
<span class="outdated">{{ <span class="outdated">{{
$d(t.warningDate.datetime, "short") $d(t.warningDate.datetime, "short")

View File

@@ -23,9 +23,7 @@
<td> <td>
<div class="workflow"> <div class="workflow">
<div class="breadcrumb"> <div class="breadcrumb">
<i <i class="fa fa-circle me-1 text-chill-yellow mx-2" />
class="fa fa-circle me-1 text-chill-yellow mx-2"
/>
<span class="mx-2">{{ getStep(w) }}</span> <span class="mx-2">{{ getStep(w) }}</span>
</div> </div>
<span <span

View File

@@ -37,11 +37,7 @@
</h4> </h4>
</td> </td>
<td> <td>
<span <span v-for="person in w.persons" class="me-1" :key="person.id">
v-for="person in w.persons"
class="me-1"
:key="person.id"
>
<on-the-fly <on-the-fly
:type="person.type" :type="person.type"
:id="person.id" :id="person.id"
@@ -52,11 +48,7 @@
</span> </span>
</td> </td>
<td> <td>
<div <div class="btn-group-vertical" role="group" aria-label="Actions">
class="btn-group-vertical"
role="group"
aria-label="Actions"
>
<a class="btn btn-sm btn-update" :href="getUrl(w)"> <a class="btn btn-sm btn-update" :href="getUrl(w)">
{{ {{
$t("show_entity", { $t("show_entity", {

View File

@@ -10,7 +10,7 @@
v-model="radioType" v-model="radioType"
value="person" value="person"
/> />
{{ $t("onthefly.create.person") }} {{ trans(ONTHEFLY_CREATE_PERSON) }}
</label> </label>
</a> </a>
</li> </li>
@@ -24,7 +24,7 @@
v-model="radioType" v-model="radioType"
value="thirdparty" value="thirdparty"
/> />
{{ $t("onthefly.create.thirdparty") }} {{ trans(ONTHEFLY_CREATE_THIRDPARTY) }}
</label> </label>
</a> </a>
</li> </li>
@@ -46,64 +46,66 @@
/> />
</div> </div>
</template> </template>
<script setup>
<script> import { ref, computed, onMounted } from "vue";
import OnTheFlyPerson from "ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue"; import OnTheFlyPerson from "ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue";
import OnTheFlyThirdparty from "ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue"; import OnTheFlyThirdparty from "ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue";
import {
trans,
ONTHEFLY_CREATE_PERSON,
ONTHEFLY_CREATE_THIRDPARTY,
} from "translator";
export default { const props = defineProps({
name: "OnTheFlyCreate", action: String,
props: ["action", "allowedTypes", "query"], allowedTypes: Array,
components: { query: String,
OnTheFlyPerson, });
OnTheFlyThirdparty,
const type = ref(null);
const radioType = computed({
get: () => type.value,
set: (val) => {
type.value = val;
console.log("## type:", val, ", action:", props.action);
}, },
data() { });
return {
type: null, const castPerson = ref(null);
}; const castThirdparty = ref(null);
},
computed: { onMounted(() => {
radioType: { type.value =
set(type) { props.allowedTypes.length === 1 && props.allowedTypes.includes("thirdparty")
this.type = type;
console.log("## type:", type, ", action:", this.action);
},
get() {
return this.type;
},
},
},
mounted() {
this.type =
this.allowedTypes.length === 1 &&
this.allowedTypes.includes("thirdparty")
? "thirdparty" ? "thirdparty"
: "person"; : "person";
}, });
methods: {
isActive(tab) { function isActive(tab) {
return this.type === tab ? true : false; return type.value === tab;
}, }
castDataByType() {
switch (this.radioType) { function castDataByType() {
switch (radioType.value) {
case "person": case "person":
return this.$refs.castPerson.$data.person; return castPerson.value.$data.person;
case "thirdparty": case "thirdparty":
let data = this.$refs.castThirdparty.$data.thirdparty; let data = castThirdparty.value.$data.thirdparty;
if (data.address !== undefined && data.address !== null) { if (data.address !== undefined && data.address !== null) {
data.address = { id: data.address.address_id }; data.address = { id: data.address.address_id };
} else { } else {
data.address = null; data.address = null;
} }
return data; return data;
default: default:
throw Error("Invalid type of entity"); throw Error("Invalid type of entity");
} }
}, }
},
}; defineExpose({
castDataByType,
});
</script> </script>
<style lang="css" scoped> <style lang="css" scoped>

View File

@@ -9,7 +9,7 @@
class="btn btn-sm" class="btn btn-sm"
target="_blank" target="_blank"
:class="classAction" :class="classAction"
:title="$t(titleAction)" :title="trans(titleAction)"
@click="openModal" @click="openModal"
> >
{{ buttonText }}<span v-if="isDead"> ()</span> {{ buttonText }}<span v-if="isDead"> ()</span>
@@ -23,10 +23,10 @@
> >
<template #header> <template #header>
<h3 v-if="parent" class="modal-title"> <h3 v-if="parent" class="modal-title">
{{ $t(titleModal, { q: parent.text }) }} {{ trans(titleModal, { q: parent.text }) }}
</h3> </h3>
<h3 v-else class="modal-title"> <h3 v-else class="modal-title">
{{ $t(titleModal) }} {{ trans(titleModal) }}
</h3> </h3>
</template> </template>
@@ -38,7 +38,7 @@
ref="castPerson" ref="castPerson"
/> />
<div v-if="hasResourceComment"> <div v-if="hasResourceComment">
<h3>{{ $t("onthefly.resource_comment_title") }}</h3> <h3>{{ trans(ONTHEFLY_RESOURCE_COMMENT_TITLE) }}</h3>
<blockquote class="chill-user-quote"> <blockquote class="chill-user-quote">
{{ parent.comment }} {{ parent.comment }}
</blockquote> </blockquote>
@@ -53,7 +53,7 @@
ref="castThirdparty" ref="castThirdparty"
/> />
<div v-if="hasResourceComment"> <div v-if="hasResourceComment">
<h3>{{ $t("onthefly.resource_comment_title") }}</h3> <h3>{{ trans(ONTHEFLY_RESOURCE_COMMENT_TITLE) }}</h3>
<blockquote class="chill-user-quote"> <blockquote class="chill-user-quote">
{{ parent.comment }} {{ parent.comment }}
</blockquote> </blockquote>
@@ -82,65 +82,82 @@
<a <a
v-if="action === 'show'" v-if="action === 'show'"
:href="buildLocation(id, type)" :href="buildLocation(id, type)"
:title="$t(titleMessage)" :title="trans(titleMessage)"
class="btn btn-show" class="btn btn-show"
>{{ $t(buttonMessage) }} >{{ trans(buttonMessage) }}
</a> </a>
<a v-else class="btn btn-save" @click="saveAction"> <a v-else class="btn btn-save" @click="saveAction">
{{ $t("action.save") }} {{ trans(ACTION_SAVE) }}
</a> </a>
</template> </template>
</modal> </modal>
</teleport> </teleport>
</template> </template>
<script setup>
<script> import { ref, computed, defineEmits, defineProps } from "vue";
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue"; import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
import OnTheFlyCreate from "./Create.vue"; import OnTheFlyCreate from "./Create.vue";
import OnTheFlyPerson from "ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue"; import OnTheFlyPerson from "ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue";
import OnTheFlyThirdparty from "ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue"; import OnTheFlyThirdparty from "ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue";
import {
trans,
ACTION_SHOW,
ACTION_EDIT,
ACTION_CREATE,
ACTION_ADDCONTACT,
ONTHEFLY_CREATE_TITLE_DEFAULT,
ONTHEFLY_CREATE_TITLE_PERSON,
ONTHEFLY_CREATE_TITLE_THIRDPARTY,
ONTHEFLY_SHOW_PERSON,
ONTHEFLY_SHOW_THIRDPARTY,
ONTHEFLY_EDIT_PERSON,
ONTHEFLY_EDIT_THIRDPARTY,
ONTHEFLY_ADDCONTACT_TITLE,
ACTION_REDIRECT_PERSON,
ACTION_REDIRECT_THIRDPARTY,
ONTHEFLY_SHOW_FILE_PERSON,
ONTHEFLY_SHOW_FILE_THIRDPARTY,
ONTHEFLY_SHOW_FILE_DEFAULT,
ONTHEFLY_RESOURCE_COMMENT_TITLE,
ACTION_SAVE,
} from "translator";
export default { const props = defineProps({
name: "OnTheFly", type: String,
components: { id: [String, Number],
Modal, action: String,
OnTheFlyPerson, buttonText: String,
OnTheFlyThirdparty, displayBadge: Boolean,
OnTheFlyCreate, isDead: Boolean,
}, parent: Object,
props: [ allowedTypes: Array,
"type", query: String,
"id", });
"action",
"buttonText", const emit = defineEmits(["saveFormOnTheFly"]);
"displayBadge",
"isDead", const modal = ref({
"parent",
"allowedTypes",
"query",
],
emits: ["saveFormOnTheFly"],
data() {
return {
modal: {
showModal: false, showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl", modalDialogClass: "modal-dialog-scrollable modal-xl",
}, });
};
}, const castPerson = ref();
computed: { const castThirdparty = ref();
hasResourceComment() { const castNew = ref();
const hasResourceComment = computed(() => {
return ( return (
typeof this.parent !== "undefined" && typeof props.parent !== "undefined" &&
this.parent !== null && props.parent !== null &&
this.action === "show" && props.action === "show" &&
this.parent.type === "accompanying_period_resource" && props.parent.type === "accompanying_period_resource" &&
this.parent.comment !== null && props.parent.comment !== null &&
this.parent.comment !== "" props.parent.comment !== ""
); );
}, });
classAction() {
switch (this.action) { const classAction = computed(() => {
switch (props.action) {
case "show": case "show":
return "btn-show"; return "btn-show";
case "edit": case "edit":
@@ -152,114 +169,125 @@ export default {
default: default:
return ""; return "";
} }
},
titleAction() {
switch (this.action) {
case "show":
return "action.show";
case "edit":
return "action.edit";
case "create":
return "action.create";
case "addContact":
return "action.addContact";
default:
return "";
}
},
titleCreate() {
if (typeof this.allowedTypes === "undefined") {
return "onthefly.create.title.default";
}
return this.allowedTypes.every((t) => t === "person")
? "onthefly.create.title.person"
: this.allowedTypes.every((t) => t === "thirdparty")
? "onthefly.create.title.thirdparty"
: "onthefly.create.title.default";
},
titleModal() {
switch (this.action) {
case "show":
return "onthefly.show." + this.type;
case "edit":
return "onthefly.edit." + this.type;
case "create":
return this.titleCreate;
case "addContact":
return "onthefly.addContact.title";
default:
return "";
}
},
titleMessage() {
switch (this.type) {
case "person":
return "action.redirect." + this.type;
case "thirdparty":
return "action.redirect." + this.type;
default:
return "";
}
},
buttonMessage() {
switch (this.type) {
case "person":
return "onthefly.show.file_" + this.type;
case "thirdparty":
return "onthefly.show.file_" + this.type;
}
},
isDisplayBadge() {
return this.displayBadge === true && this.buttonText !== null;
},
badgeType() {
return "entity-" + this.type + " badge-" + this.type;
},
getReturnPath() {
return `?returnPath=${window.location.pathname}${window.location.search}${window.location.hash}`;
},
},
methods: {
closeModal() {
this.modal.showModal = false;
},
openModal() {
// console.log('## OPEN ON THE FLY MODAL');
// console.log('## type:', this.type, ', action:', this.action);
this.modal.showModal = true;
this.$nextTick(function () {
//this.$refs.search.focus();
}); });
},
changeActionTo(action) { const titleAction = computed(() => {
this.$data.action = action; switch (props.action) {
}, case "show":
saveAction() { return ACTION_SHOW;
// console.log('saveAction button: create/edit action with', this.type); case "edit":
let type = this.type, return ACTION_EDIT;
case "create":
return ACTION_CREATE;
case "addContact":
return ACTION_ADDCONTACT;
default:
return "";
}
});
const titleCreate = computed(() => {
if (typeof props.allowedTypes === "undefined") {
return ONTHEFLY_CREATE_TITLE_DEFAULT;
}
return props.allowedTypes.every((t) => t === "person")
? ONTHEFLY_CREATE_TITLE_PERSON
: props.allowedTypes.every((t) => t === "thirdparty")
? ONTHEFLY_CREATE_TITLE_THIRDPARTY
: ONTHEFLY_CREATE_TITLE_DEFAULT;
});
const titleModal = computed(() => {
switch (props.action) {
case "show":
if (props.type == "person") {
return ONTHEFLY_SHOW_PERSON;
} else if (props.type == "thirdparty") {
return ONTHEFLY_SHOW_THIRDPARTY;
}
break;
case "edit":
if (props.type == "person") {
return ONTHEFLY_EDIT_PERSON;
} else if (props.type == "thirdparty") {
return ONTHEFLY_EDIT_THIRDPARTY;
}
break;
case "create":
return titleCreate.value;
case "addContact":
return ONTHEFLY_ADDCONTACT_TITLE;
default:
break;
}
return "";
});
const titleMessage = computed(() => {
switch (props.type) {
case "person":
return ACTION_REDIRECT_PERSON;
case "thirdparty":
return ACTION_REDIRECT_THIRDPARTY;
default:
return "";
}
});
const buttonMessage = computed(() => {
switch (props.type) {
case "person":
return ONTHEFLY_SHOW_FILE_PERSON;
case "thirdparty":
return ONTHEFLY_SHOW_FILE_THIRDPARTY;
default:
return ONTHEFLY_SHOW_FILE_DEFAULT;
}
});
const isDisplayBadge = computed(() => {
return props.displayBadge === true && props.buttonText !== null;
});
const badgeType = computed(() => {
return "entity-" + props.type + " badge-" + props.type;
});
const getReturnPath = computed(() => {
return `?returnPath=${window.location.pathname}${window.location.search}${window.location.hash}`;
});
function closeModal() {
modal.value.showModal = false;
}
function openModal() {
modal.value.showModal = true;
}
function changeActionTo(action) {
console.log(action);
// Not reactive in setup, but you can emit or use a ref if needed
}
function saveAction() {
let type = props.type,
data = {}; data = {};
switch (type) { switch (type) {
case "person": case "person":
data = this.$refs.castPerson.$data.person; data = castPerson.value?.$data.person;
console.log("person data are", data);
break; break;
case "thirdparty": case "thirdparty":
data = this.$refs.castThirdparty.$data.thirdparty; data = castThirdparty.value?.$data.thirdparty;
/* never executed ? */
break; break;
default: default:
if (typeof this.type === "undefined") { if (typeof props.type === "undefined") {
// action=create or addContact if (props.action === "addContact") {
// console.log('will rewrite data');
if (this.action === "addContact") {
type = "thirdparty"; type = "thirdparty";
data = this.$refs.castThirdparty.$data.thirdparty; data = castThirdparty.value?.$data.thirdparty;
// console.log('data original', data);
data.parent = { data.parent = {
type: "thirdparty", type: "thirdparty",
id: this.parent.id, id: props.parent.id,
}; };
data.civility = data.civility =
data.civility !== null data.civility !== null
@@ -268,16 +296,11 @@ export default {
id: data.civility.id, id: data.civility.id,
} }
: null; : null;
data.profession = data.profession = data.profession !== "" ? data.profession : "";
data.profession !== "" ? data.profession : "";
} else { } else {
type = this.$refs.castNew.radioType; type = castNew.value.radioType;
data = this.$refs.castNew.castDataByType(); data = castNew.value.castDataByType();
// console.log('type', type); if (typeof data.civility !== "undefined" && null !== data.civility) {
if (
typeof data.civility !== "undefined" &&
null !== data.civility
) {
data.civility = data.civility =
data.civility !== null data.civility !== null
? { ? {
@@ -290,34 +313,37 @@ export default {
typeof data.profession !== "undefined" && typeof data.profession !== "undefined" &&
"" !== data.profession "" !== data.profession
) { ) {
data.profession = data.profession = data.profession !== "" ? data.profession : "";
data.profession !== ""
? data.profession
: "";
} }
// console.log('onthefly data', data);
} }
} else { } else {
throw "error with object type"; throw "error with object type";
} }
} }
// pass datas to parent emit("saveFormOnTheFly", { type: type, data: data });
this.$emit("saveFormOnTheFly", { type: type, data: data });
},
buildLocation(id, type) {
if (type === "person") {
// TODO i18n
return encodeURI(
`/fr/person/${id}/general${this.getReturnPath}`,
);
} else if (type === "thirdparty") {
return encodeURI(
`/fr/3party/3party/${id}/view${this.getReturnPath}`,
);
} }
},
}, function buildLocation(id, type) {
}; if (type === "person") {
return encodeURI(`/fr/person/${id}/general${getReturnPath.value}`);
} else if (type === "thirdparty") {
return encodeURI(`/fr/3party/3party/${id}/view${getReturnPath.value}`);
}
}
defineExpose({
openModal,
closeModal,
changeActionTo,
saveAction,
castPerson,
castThirdparty,
castNew,
hasResourceComment,
modal,
isDisplayBadge,
Modal,
});
</script> </script>
<style lang="css" scoped> <style lang="css" scoped>

View File

@@ -1,22 +1,34 @@
<template> <template>
<ul :class="listClasses" v-if="picked.length && displayPicked"> <div class="grey-card">
<li v-for="p in picked" @click="removeEntity(p)" :key="p.type + p.id"> <ul :class="listClasses" v-if="picked.length > 0 && displayPicked">
<li
v-for="p in picked"
@click="removeEntity(p)"
:key="p === 'me' ? 'me' : p.type + p.id"
>
<span <span
v-if="'me' === p" v-if="'me' === p"
class="chill_denomination current-user updatedBy" class="chill_denomination current-user updatedBy"
>{{ trans(USER_CURRENT_USER) }}</span >{{ trans(USER_CURRENT_USER) }}</span
> >
<span v-else class="chill_denomination">{{ p.text }}</span> <span
v-else
:class="getBadgeClass(p)"
class="chill_denomination"
:style="getBadgeStyle(p)"
>
{{ p.text }}
</span>
</li> </li>
</ul> </ul>
<ul class="record_actions"> <ul class="record_actions">
<li v-if="isCurrentUserPicker" class="btn btn-sm btn-misc"> <li v-if="isCurrentUserPicker" class="btn btn-sm btn-misc">
<label class="flex items-center gap-2"> <label class="flex items-center gap-2">
<input <input
:checked="picked.indexOf('me') >= 0 ? true : null" :checked="isMePicked"
ref="itsMeCheckbox" ref="itsMeCheckbox"
:type="multiple ? 'checkbox' : 'radio'" :type="multiple ? 'checkbox' : 'radio'"
@change="selectItsMe" @change="selectItsMe($event as InputEvent)"
/> />
{{ trans(USER_CURRENT_USER) }} {{ trans(USER_CURRENT_USER) }}
</label> </label>
@@ -27,94 +39,287 @@
:key="uniqid" :key="uniqid"
:buttonTitle="translatedListOfTypes" :buttonTitle="translatedListOfTypes"
:modalTitle="translatedListOfTypes" :modalTitle="translatedListOfTypes"
ref="addPersons"
@addNewPersons="addNewEntity" @addNewPersons="addNewEntity"
> >
</add-persons> </add-persons>
</li> </li>
</ul> </ul>
<ul class="list-suggest add-items inline">
<li v-for="s in suggested" :key="s.id" @click="addNewSuggested(s)"> <ul class="badge-suggest add-items inline" style="float: right">
<span>{{ s.text }}</span> <li
v-for="s in suggested"
:key="s.type + s.id"
@click="addNewSuggested(s)"
>
<span :class="getBadgeClass(s)" :style="getBadgeStyle(s)">
{{ s.text }}
</span>
</li> </li>
</ul> </ul>
</div>
</template> </template>
<script setup> <script lang="ts" setup>
import { ref, computed } from "vue"; import {
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue"; // eslint-disable-line ref,
import { appMessages } from "./i18n"; computed,
import { trans, USER_CURRENT_USER } from "translator"; defineProps,
defineEmits,
defineComponent,
withDefaults,
} from "vue";
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
import {
Entities,
EntitiesOrMe,
EntityType,
SearchOptions,
} from "ChillPersonAssets/types";
import {
PICK_ENTITY_MODAL_TITLE,
PICK_ENTITY_USER,
PICK_ENTITY_USER_GROUP,
PICK_ENTITY_PERSON,
PICK_ENTITY_THIRDPARTY,
USER_CURRENT_USER,
trans,
} from "translator";
import { addNewEntities } from "ChillMainAssets/types";
const props = defineProps({ defineComponent({
multiple: Boolean, components: {
types: Array, AddPersons,
picked: Array, },
uniqid: String,
removableIfSet: { type: Boolean, default: true },
displayPicked: { type: Boolean, default: true },
suggested: { type: Array, default: () => [] },
label: String,
isCurrentUserPicker: { type: Boolean, default: false },
}); });
const props = withDefaults(
defineProps<{
multiple: boolean;
types: EntityType[];
picked: EntitiesOrMe[];
uniqid: string;
removableIfSet?: boolean;
displayPicked?: boolean;
suggested?: Entities[];
label?: string;
isCurrentUserPicker?: boolean;
}>(),
{ isCurrentUserPicker: false, displayPicked: true, removableIfSet: true },
);
const emit = defineEmits([ const emits = defineEmits<{
"addNewEntity", (e: "addNewEntity", payload: { entity: EntitiesOrMe }): void;
"removeEntity", (e: "removeEntity", payload: { entity: EntitiesOrMe }): void;
"addNewEntityProcessEnded", (e: "addNewEntityProcessEnded"): void;
]); }>();
const itsMeCheckbox = ref(null); const itsMeCheckbox = ref<null | HTMLInputElement>(null);
const addPersons = ref(null); const addPersons = ref();
const addPersonsOptions = computed(() => ({ const addPersonsOptions = computed(
() =>
({
uniq: !props.multiple, uniq: !props.multiple,
type: props.types, type: props.types,
priority: null, priority: null,
button: { size: "btn-sm", class: "btn-submit" }, button: {
})); size: "btn-sm",
class: "btn-submit",
},
}) as SearchOptions,
);
const isMePicked = computed<boolean>(() => props.picked.indexOf("me") >= 0);
const translatedListOfTypes = computed(() => { const translatedListOfTypes = computed(() => {
if (props.label) return props.label; if (props.label !== undefined && props.label !== "") {
let trans = props.types.map((t) => return props.label;
props.multiple }
? appMessages.fr.pick_entity[t].toLowerCase()
: appMessages.fr.pick_entity[t + "_one"].toLowerCase(), const translatedTypes = props.types.map((type: EntityType) => {
); switch (type) {
return props.multiple case "user":
? appMessages.fr.pick_entity.modal_title + trans.join(", ") return trans(PICK_ENTITY_USER, {
: appMessages.fr.pick_entity.modal_title_one + trans.join(", "); count: props.multiple ? 2 : 1,
});
case "person":
return trans(PICK_ENTITY_PERSON, {
count: props.multiple ? 2 : 1,
});
case "thirdparty":
return trans(PICK_ENTITY_THIRDPARTY, {
count: props.multiple ? 2 : 1,
});
case "user_group":
return trans(PICK_ENTITY_USER_GROUP, {
count: props.multiple ? 2 : 1,
});
}
});
return `${trans(PICK_ENTITY_MODAL_TITLE, {
count: props.multiple ? 2 : 1,
})} ${translatedTypes.join(", ")}`;
}); });
const listClasses = computed(() => ({ const listClasses = computed(() => ({
"list-suggest": true, "badge-suggest": true,
"remove-items": props.removableIfSet, "remove-items": props.removableIfSet,
inline: true,
})); }));
const selectItsMe = (event) => const selectItsMe = (event: InputEvent): void => {
event.target.checked ? addNewSuggested("me") : removeEntity("me"); const target = event.target as HTMLInputElement;
if (target.checked) {
const addNewSuggested = (entity) => { addNewSuggested("me");
emit("addNewEntity", { entity }); } else {
removeEntity("me");
}
}; };
const addNewEntity = ({ selected, modal }) => { function addNewSuggested(entity: EntitiesOrMe) {
selected.forEach((item) => emit("addNewEntity", { entity: item.result })); emits("addNewEntity", { entity });
}
function addNewEntity({ selected }: addNewEntities) {
Object.values(selected).forEach((item) => {
emits("addNewEntity", { entity: item.result });
});
addPersons.value?.resetSearch(); addPersons.value?.resetSearch();
modal.showModal = false;
emit("addNewEntityProcessEnded");
};
const removeEntity = (entity) => { emits("addNewEntityProcessEnded");
}
const removeEntity = (entity: EntitiesOrMe): void => {
if (!props.removableIfSet) return; if (!props.removableIfSet) return;
if (entity === "me" && itsMeCheckbox.value) { if (entity === "me" && itsMeCheckbox.value) {
itsMeCheckbox.value.checked = false; itsMeCheckbox.value.checked = false;
} }
emit("removeEntity", { entity }); emits("removeEntity", { entity });
}; };
function getBadgeClass(entities: Entities) {
if (entities.type !== "user_group") {
return entities.type;
}
return "";
}
function getBadgeStyle(entities: Entities) {
if (entities.type === "user_group") {
return [
`ul.badge-suggest li > span {
color: ${entities.foregroundColor}!important;
border-bottom-color: ${entities.backgroundColor};
}`,
];
}
return [];
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.grey-card {
background: #f8f9fa;
border-radius: 8px;
padding: 1.5rem;
min-height: 160px;
}
.btn-check:checked + .btn,
:not(.btn-check) + .btn:active,
.btn:first-child:active,
.btn.active,
.btn.show {
color: white;
box-shadow: 0 0 0 0.2rem var(--bs-chill-green);
outline: 0;
}
.as-user-group {
display: inline-block;
}
ul.badge-suggest {
list-style-type: none;
padding-left: 0;
margin-bottom: 0px;
}
ul.badge-suggest li > span {
white-space: normal;
text-align: start;
margin-bottom: 3px;
}
ul.badge-suggest.inline li {
display: inline-block;
margin-right: 0.2em;
}
ul.badge-suggest.add-items li {
position: relative;
}
ul.badge-suggest.add-items li span {
cursor: pointer;
padding-left: 2rem;
}
ul.badge-suggest.add-items li span:hover {
color: #ced4da;
}
ul.badge-suggest.add-items li > span:before {
font: normal normal normal 13px ForkAwesome;
margin-right: 1.8em;
content: "\f067";
color: var(--bs-success);
position: absolute;
display: block;
top: 50%;
left: 0.75rem;
-webkit-transform: translateY(-50%);
-moz-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
ul.badge-suggest.remove-items li {
position: relative;
}
ul.badge-suggest.remove-items li span {
cursor: pointer;
padding-left: 2rem;
}
ul.badge-suggest.remove-items li span:hover {
color: #ced4da;
}
ul.badge-suggest.remove-items li > span:before {
font: normal normal normal 13px ForkAwesome;
margin-right: 1.8em;
content: "\f1f8";
color: var(--bs-danger);
position: absolute;
display: block;
top: 50%;
left: 0.75rem;
-webkit-transform: translateY(-50%);
-moz-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
ul.badge-suggest li > span {
margin: 0.2rem 0.1rem;
display: inline-block;
padding: 0 1em 0 2.2em !important;
background-color: #fff;
border: 1px solid #dee2e6;
border-bottom-width: 3px;
border-bottom-style: solid;
border-radius: 6px;
font-size: 0.75em;
font-weight: 700;
}
ul.badge-suggest li > span.person {
border-bottom-color: #43b29d;
}
ul.badge-suggest li > span.thirdparty {
border-bottom-color: rgb(198.9, 72, 98.1);
}
.current-user { .current-user {
color: var(--bs-body-color); color: var(--bs-body-color);
background-color: var(--bs-chill-l-gray) !important; background-color: var(--bs-chill-l-gray) !important;

View File

@@ -61,9 +61,7 @@ export default {
}, },
methods: { methods: {
transName(value) { transName(value) {
return value.code && value.name return value.code && value.name ? `${value.name} (${value.code})` : "";
? `${value.name} (${value.code})`
: "";
}, },
selectCity(city) { selectCity(city) {
this.$emit("selectCity", city); this.$emit("selectCity", city);
@@ -86,9 +84,7 @@ export default {
searchCities(query, this.country, controller) searchCities(query, this.country, controller)
.then((newCities) => { .then((newCities) => {
this.cities = this.cities.filter( this.cities = this.cities.filter((city) => city.id === this.picked);
(city) => city.id === this.picked,
);
newCities.forEach((item) => { newCities.forEach((item) => {
this.cities.push(item); this.cities.push(item);
}); });

View File

@@ -10,9 +10,7 @@ const props = defineProps<SavedExportButtonsConfig>();
</script> </script>
<template> <template>
<generate-button <generate-button :saved-export-uuid="props.savedExportUuid"></generate-button>
:saved-export-uuid="props.savedExportUuid"
></generate-button>
</template> </template>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@@ -125,9 +125,7 @@ const onObjectNewStatusCallback = async function (): Promise<void> {
const onClickGenerate = async (): Promise<void> => { const onClickGenerate = async (): Promise<void> => {
emits("generate"); emits("generate");
exportGeneration.value = await generateFromSavedExport( exportGeneration.value = await generateFromSavedExport(props.savedExportUuid);
props.savedExportUuid,
);
onObjectNewStatusCallback(); onObjectNewStatusCallback();

View File

@@ -110,9 +110,7 @@ const filteredDocuments = computed<GenericDocForAccompanyingPeriod[]>(() => {
return false; return false;
} }
return needles.every((n: string) => return needles.every((n: string) => title.toLowerCase().includes(n));
title.toLowerCase().includes(n),
);
}) })
.filter((genericDoc: GenericDocForAccompanyingPeriod) => { .filter((genericDoc: GenericDocForAccompanyingPeriod) => {
if (placesFilter.value.length === 0) { if (placesFilter.value.length === 0) {
@@ -153,8 +151,7 @@ const filteredDocuments = computed<GenericDocForAccompanyingPeriod[]>(() => {
aria-controls="filterOrderCollapse" aria-controls="filterOrderCollapse"
> >
<strong <strong
><i class="fa fa-fw fa-filter"></i>Filtrer la ><i class="fa fa-fw fa-filter"></i>Filtrer la liste</strong
liste</strong
> >
</button> </button>
</h2> </h2>
@@ -179,10 +176,7 @@ const filteredDocuments = computed<GenericDocForAccompanyingPeriod[]>(() => {
placeholder="Chercher dans la liste" placeholder="Chercher dans la liste"
class="form-control" class="form-control"
/> />
<button <button type="submit" class="btn btn-misc">
type="submit"
class="btn btn-misc"
>
<i class="fa fa-search"></i> <i class="fa fa-search"></i>
</button> </button>
</div> </div>
@@ -190,9 +184,7 @@ const filteredDocuments = computed<GenericDocForAccompanyingPeriod[]>(() => {
</div> </div>
<div class="row my-2"> <div class="row my-2">
<legend <legend class="col-form-label col-sm-4 required">
class="col-form-label col-sm-4 required"
>
Date du document Date du document
</legend> </legend>
<div class="col-sm-8 pt-1"> <div class="col-sm-8 pt-1">
@@ -218,15 +210,9 @@ const filteredDocuments = computed<GenericDocForAccompanyingPeriod[]>(() => {
</div> </div>
<div class="row my-2"> <div class="row my-2">
<div class="col-sm-4 col-form-label"> <div class="col-sm-4 col-form-label">Filtrer par</div>
Filtrer par
</div>
<div class="col-sm-8 pt-2"> <div class="col-sm-8 pt-2">
<div <div class="form-check" v-for="p in availablePlaces" :key="p">
class="form-check"
v-for="p in availablePlaces"
:key="p"
>
<input <input
type="checkbox" type="checkbox"
v-model="placesFilter" v-model="placesFilter"
@@ -234,9 +220,7 @@ const filteredDocuments = computed<GenericDocForAccompanyingPeriod[]>(() => {
class="form-check-input" class="form-check-input"
:value="p" :value="p"
/> />
<label class="form-check-label">{{ <label class="form-check-label">{{ placeTrans(p) }}</label>
placeTrans(p)
}}</label>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -81,16 +81,8 @@ const clickOnAddButton = () => {
rgba(25, 135, 84, 1) 0px, rgba(25, 135, 84, 1) 0px,
rgba(25, 135, 84, 0) 9px rgba(25, 135, 84, 0) 9px
), ),
linear-gradient( linear-gradient(0deg, rgba(25, 135, 84, 1) 0px, rgba(25, 135, 84, 0) 9px),
0deg, linear-gradient(90deg, rgba(25, 135, 84, 1) 0px, rgba(25, 135, 84, 0) 9px);
rgba(25, 135, 84, 1) 0px,
rgba(25, 135, 84, 0) 9px
),
linear-gradient(
90deg,
rgba(25, 135, 84, 1) 0px,
rgba(25, 135, 84, 0) 9px
);
} }
} }
</style> </style>

View File

@@ -97,8 +97,8 @@ defineExpose({ openModal, closeModal });
@click="onConfirm" @click="onConfirm"
> >
<template v-if="numberOfPicked > 1"> <template v-if="numberOfPicked > 1">
<i class="fa fa-plus"></i> Ajouter <i class="fa fa-plus"></i> Ajouter {{ numberOfPicked }} pièces
{{ numberOfPicked }} pièces jointes jointes
</template> </template>
<template v-else> <template v-else>
<i class="fa fa-plus"></i> Ajouter une pièce jointe <i class="fa fa-plus"></i> Ajouter une pièce jointe

View File

@@ -81,17 +81,12 @@ window.addEventListener("DOMContentLoaded", () => {
"this document is already attached to the workflow", "this document is already attached to the workflow",
genericDoc, genericDoc,
); );
this.$toast.error( this.$toast.error("Ce document est déjà attaché au workflow");
"Ce document est déjà attaché au workflow",
);
return; return;
} }
try { try {
const attachment = await create_attachment( const attachment = await create_attachment(workflowId, genericDoc);
workflowId,
genericDoc,
);
this.$data.attachments.push(attachment); this.$data.attachments.push(attachment);
} catch (error) { } catch (error) {
console.error(error); console.error(error);

View File

@@ -1,7 +1,6 @@
<template> <template>
<div v-if="props.address.isNoAddress" class="alert alert-info"> <div v-if="props.address.isNoAddress" class="alert alert-info">
Cette adresse est incomplète. La position géographique est Cette adresse est incomplète. La position géographique est approximative.
approximative.
</div> </div>
<div <div
v-if="props.address.point !== null" v-if="props.address.point !== null"
@@ -10,9 +9,7 @@
></div> ></div>
<p> <p>
Voir sur Voir sur
<a :href="makeUrlGoogleMap(props.address)" target="_blank" <a :href="makeUrlGoogleMap(props.address)" target="_blank">Google Maps</a>
>Google Maps</a
>
<a :href="makeUrlOsm(props.address)" target="_blank">OSM</a> <a :href="makeUrlOsm(props.address)" target="_blank">OSM</a>
</p> </p>
</template> </template>

View File

@@ -12,8 +12,7 @@
}" }"
> >
<p v-if="props.address.refStatus === 'to_review'"> <p v-if="props.address.refStatus === 'to_review'">
<i class="fa fa-warning"></i> L'adresse de référence a été <i class="fa fa-warning"></i> L'adresse de référence a été modifiée.
modifiée.
</p> </p>
<p v-if="props.address.refStatus === 'reviewed'"> <p v-if="props.address.refStatus === 'reviewed'">
L'adresse est conservée, mais diffère de l'adresse de référence. L'adresse est conservée, mais diffère de l'adresse de référence.
@@ -21,8 +20,7 @@
<template <template
v-if=" v-if="
props.address.addressReference.street !== props.address.addressReference.street !== props.address.street ||
props.address.street ||
props.address.addressReference.streetNumber !== props.address.addressReference.streetNumber !==
props.address.streetNumber props.address.streetNumber
" "
@@ -30,22 +28,18 @@
<template v-if="props.address.country.code === 'BE'"> <template v-if="props.address.country.code === 'BE'">
<div class="difference"> <div class="difference">
<span class="old" <span class="old"
>{{ props.address.street }} >{{ props.address.street }} {{ props.address.streetNumber }}</span
{{ props.address.streetNumber }}</span
> >
<span class="new" <span class="new"
>{{ props.address.addressReference.street }} >{{ props.address.addressReference.street }}
{{ {{ props.address.addressReference.streetNumber }}</span
props.address.addressReference.streetNumber
}}</span
> >
</div> </div>
</template> </template>
<template v-else> <template v-else>
<div class="difference"> <div class="difference">
<span class="old" <span class="old"
>{{ props.address.streetNumber }} >{{ props.address.streetNumber }} {{ props.address.street }}</span
{{ props.address.street }}</span
> >
<span class="new" <span class="new"
>{{ props.address.addressReference.streetNumber }} >{{ props.address.addressReference.streetNumber }}
@@ -88,12 +82,8 @@
{{ props.address.point.coordinates[1] }}</span {{ props.address.point.coordinates[1] }}</span
> >
<span class="new" <span class="new"
>{{ >{{ props.address.addressReference.point.coordinates[0] }}
props.address.addressReference.point.coordinates[0] {{ props.address.addressReference.point.coordinates[1] }}</span
}}
{{
props.address.addressReference.point.coordinates[1]
}}</span
> >
</div> </div>
</template> </template>
@@ -105,18 +95,12 @@
</button> </button>
</li> </li>
<li v-if="props.address.refStatus === 'to_review'"> <li v-if="props.address.refStatus === 'to_review'">
<button <button class="btn btn-sm btn-primary" @click="keepCurrentAddress">
class="btn btn-sm btn-primary"
@click="keepCurrentAddress"
>
Conserver Conserver
</button> </button>
</li> </li>
<li v-if="props.address.refStatus === 'reviewed'"> <li v-if="props.address.refStatus === 'reviewed'">
<button <button class="btn btn-sm btn-primary" @click="backToReview">
class="btn btn-sm btn-primary"
@click="backToReview"
>
Ré-examiner Ré-examiner
</button> </button>
</li> </li>

View File

@@ -32,10 +32,7 @@
</template> </template>
</span> </span>
<span <span v-if="props.entity.type === 'user'" class="badge rounded-pill bg-user">
v-if="props.entity.type === 'user'"
class="badge rounded-pill bg-user"
>
{{ trans(ACCEPTED_USERS) }} {{ trans(ACCEPTED_USERS) }}
</span> </span>

View File

@@ -49,10 +49,7 @@ onMounted(function () {
const storage = window.localStorage; const storage = window.localStorage;
const savedKind = storage.getItem(EDITOR_MODE_KEY); const savedKind = storage.getItem(EDITOR_MODE_KEY);
if ( if (null !== kind.value && (savedKind === "simple" || savedKind === "rich")) {
null !== kind.value &&
(savedKind === "simple" || savedKind === "rich")
) {
kind.value = savedKind; kind.value = savedKind;
} }
@@ -76,10 +73,7 @@ onUnmounted(function () {
/> />
</div> </div>
<div v-else> <div v-else>
<textarea <textarea v-model="value" class="form-control simple-editor"></textarea>
v-model="value"
class="form-control simple-editor"
></textarea>
</div> </div>
<button :class="toggleButtonClass" type="button" @click="toggleEditor"> <button :class="toggleButtonClass" type="button" @click="toggleEditor">

View File

@@ -5,10 +5,7 @@
<confidential :position-btn-far="true"> <confidential :position-btn-far="true">
<template #confidential-content> <template #confidential-content>
<div v-if="isMultiline === true"> <div v-if="isMultiline === true">
<p <p v-for="(l, i) in address.lines" :key="`line-${i}`">
v-for="(l, i) in address.lines"
:key="`line-${i}`"
>
{{ l }} {{ l }}
</p> </p>
<p v-if="showButtonDetails"> <p v-if="showButtonDetails">
@@ -22,10 +19,7 @@
<p v-if="'' !== address.text" class="street"> <p v-if="'' !== address.text" class="street">
{{ address.text }} {{ address.text }}
</p> </p>
<p <p v-if="null !== address.postcode" class="postcode">
v-if="null !== address.postcode"
class="postcode"
>
{{ address.postcode.code }} {{ address.postcode.code }}
{{ address.postcode.name }} {{ address.postcode.name }}
</p> </p>

View File

@@ -1,9 +1,28 @@
<template> <template>
<i :class="gender.icon" /> <i :class="['fa', genderClass, 'px-1']" />
</template> </template>
<script setup> <script setup>
import { computed } from "vue";
const props = defineProps({ const props = defineProps({
gender: Object, gender: {
type: Object,
required: true,
},
});
const genderClass = computed(() => {
switch (props.gender.genderTranslation) {
case "woman":
return "fa-venus";
case "man":
return "fa-mars";
case "both":
return "fa-neuter";
case "unknown":
return "fa-genderless";
default:
return "fa-genderless";
}
}); });
</script> </script>

View File

@@ -33,16 +33,11 @@
class="fa fa-circle me-1 text-chill-yellow" class="fa fa-circle me-1 text-chill-yellow"
> >
</i> </i>
<i <i v-if="step.isFreezed" class="fa fa-snowflake-o fa-sm me-1">
v-if="step.isFreezed"
class="fa fa-snowflake-o fa-sm me-1"
>
</i> </i>
{{ step.currentStep.text }} {{ step.currentStep.text }}
</span> </span>
<span v-if="j !== Object.keys(w.steps).length - 1"> <span v-if="j !== Object.keys(w.steps).length - 1"> </span>
</span>
</template> </template>
</div> </div>
<span <span

View File

@@ -31,12 +31,8 @@
:relatedEntityClass="props.relatedEntityClass" :relatedEntityClass="props.relatedEntityClass"
:relatedEntityId="props.relatedEntityId" :relatedEntityId="props.relatedEntityId"
:workflowsAvailables="props.workflowsAvailables" :workflowsAvailables="props.workflowsAvailables"
:preventDefaultMoveToGenerate=" :preventDefaultMoveToGenerate="props.preventDefaultMoveToGenerate"
props.preventDefaultMoveToGenerate :goToGenerateWorkflowPayload="props.goToGenerateWorkflowPayload"
"
:goToGenerateWorkflowPayload="
props.goToGenerateWorkflowPayload
"
:countExistingWorkflows="countWorkflows" :countExistingWorkflows="countWorkflows"
:embedded-within-list-modal="true" :embedded-within-list-modal="true"
@go-to-generate-workflow="goToGenerateWorkflow" @go-to-generate-workflow="goToGenerateWorkflow"

View File

@@ -42,21 +42,14 @@
data-bs-toggle="dropdown" data-bs-toggle="dropdown"
aria-expanded="false" aria-expanded="false"
> >
<span class="visually-hidden" <span class="visually-hidden">Liste des workflows disponibles</span>
>Liste des workflows disponibles</span
>
</button> </button>
<ul <ul class="dropdown-menu" aria-labelledby="createWorkflowButton">
class="dropdown-menu"
aria-labelledby="createWorkflowButton"
>
<li v-for="w in props.workflowsAvailables" :key="w.name"> <li v-for="w in props.workflowsAvailables" :key="w.name">
<button <button
class="dropdown-item" class="dropdown-item"
type="button" type="button"
@click.prevent=" @click.prevent="goToGenerateWorkflow($event, w.name)"
goToGenerateWorkflow($event, w.name)
"
> >
{{ w.text }} {{ w.text }}
</button> </button>

View File

@@ -1,6 +1,6 @@
<template> <template>
<transition name="modal"> <transition name="modal">
<div class="modal-mask"> <div class="modal-mask" v-if="show">
<!-- :: styles bootstrap :: --> <!-- :: styles bootstrap :: -->
<div <div
class="modal fade show" class="modal fade show"
@@ -8,7 +8,7 @@
aria-modal="true" aria-modal="true"
role="dialog" role="dialog"
> >
<div class="modal-dialog" :class="props.modalDialogClass || {}"> <div class="modal-dialog" :class="modalDialogClass || {}">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<slot name="header"></slot> <slot name="header"></slot>
@@ -23,10 +23,7 @@
<slot name="body"></slot> <slot name="body"></slot>
</div> </div>
<div class="modal-footer" v-if="!hideFooter"> <div class="modal-footer" v-if="!hideFooter">
<button <button class="btn btn-cancel" @click="emits('close')">
class="btn btn-cancel"
@click="emits('close')"
>
{{ trans(MODAL_ACTION_CLOSE) }} {{ trans(MODAL_ACTION_CLOSE) }}
</button> </button>
<slot name="footer"></slot> <slot name="footer"></slot>
@@ -53,14 +50,23 @@ import { trans, MODAL_ACTION_CLOSE } from "translator";
import { defineProps } from "vue"; import { defineProps } from "vue";
export interface ModalProps { export interface ModalProps {
modalDialogClass: object | null; modalDialogClass: string;
hideFooter: boolean; hideFooter: boolean;
} }
// Define the props defineProps({
const props = withDefaults(defineProps<ModalProps>(), { modalDialogClass: {
hideFooter: false, type: String,
modalDialogClass: null, default: "",
},
hideFooter: {
type: Boolean,
default: false,
},
show: {
type: Boolean,
default: true,
},
}); });
const emits = defineEmits<{ const emits = defineEmits<{

View File

@@ -78,8 +78,7 @@ export const multiSelectMessages = {
tag_placeholder: "Créer un nouvel élément", tag_placeholder: "Créer un nouvel élément",
select_label: '"Entrée" ou cliquez pour sélectionner', select_label: '"Entrée" ou cliquez pour sélectionner',
deselect_label: '"Entrée" ou cliquez pour désélectionner', deselect_label: '"Entrée" ou cliquez pour désélectionner',
select_group_label: select_group_label: 'Appuyer sur "Entrée" pour sélectionner ce groupe',
'Appuyer sur "Entrée" pour sélectionner ce groupe',
deselect_group_label: deselect_group_label:
'Appuyer sur "Entrée" pour désélectionner ce groupe', 'Appuyer sur "Entrée" pour désélectionner ce groupe',
selected_label: "Sélectionné", selected_label: "Sélectionné",

View File

@@ -69,6 +69,7 @@
</div> </div>
{% endif %} {% endif %}
{% block wrapping_content %}
{% block content %} {% block content %}
<div class="col-8 main_search"> <div class="col-8 main_search">
{% if app.user.isAbsent %} {% if app.user.isAbsent %}
@@ -99,6 +100,7 @@
{% include '@ChillMain/Homepage/index.html.twig' %} {% include '@ChillMain/Homepage/index.html.twig' %}
{% endblock %} {% endblock %}
{% endblock %}
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -12,6 +12,7 @@ declare(strict_types=1);
namespace Chill\MainBundle\Tests\Phonenumber; namespace Chill\MainBundle\Tests\Phonenumber;
use Chill\MainBundle\Phonenumber\PhonenumberHelper; use Chill\MainBundle\Phonenumber\PhonenumberHelper;
use libphonenumber\PhoneNumber;
use libphonenumber\PhoneNumberUtil; use libphonenumber\PhoneNumberUtil;
use Psr\Log\NullLogger; use Psr\Log\NullLogger;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
@@ -31,6 +32,7 @@ final class PhonenumberHelperTest extends KernelTestCase
public function testFormatPhonenumbers(string $defaultCarrierCode, string $phoneNumber, string $expected) public function testFormatPhonenumbers(string $defaultCarrierCode, string $phoneNumber, string $expected)
{ {
$util = PhoneNumberUtil::getInstance(); $util = PhoneNumberUtil::getInstance();
$subject = new PhonenumberHelper( $subject = new PhonenumberHelper(
new ArrayAdapter(), new ArrayAdapter(),
new ParameterBag([ new ParameterBag([
@@ -70,4 +72,47 @@ final class PhonenumberHelperTest extends KernelTestCase
'00 33 6 23 12 45 54', '00 33 6 23 12 45 54',
]; ];
} }
/**
* @dataProvider providePhoneNumbersToParse
*/
public function testParsePhonenumbers(string $defaultCarrierCode, string $phoneNumber, PhoneNumber $expected): void
{
$subject = new PhonenumberHelper(
new ArrayAdapter(),
new ParameterBag([
'chill_main.phone_helper' => [
'default_carrier_code' => $defaultCarrierCode,
],
]),
new NullLogger()
);
$actual = $subject->parse($phoneNumber);
self::assertTrue($expected->equals($actual));
}
public static function providePhoneNumbersToParse(): iterable
{
$util = PhoneNumberUtil::getInstance();
yield [
'FR',
'+32486544999',
$util->parse('+32486544999', 'FR'),
];
yield [
'FR',
'32486544999',
$util->parse('+32486544999', 'FR'),
];
yield [
'FR',
'0228858040',
$util->parse('+33228858040', 'FR'),
];
}
} }

View File

@@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Tests\Validation\Validator;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserGroup;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\MainBundle\Validation\Validator\UserGroupDoNotExclude;
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
/**
* @internal
*
* @coversNothing
*/
class UserGroupDoNotExcludeTest extends ConstraintValidatorTestCase
{
protected function createValidator()
{
return new UserGroupDoNotExclude(
new class () implements TranslatableStringHelperInterface {
public function localize(array $translatableStrings): ?string
{
return $translatableStrings['fr'];
}
}
);
}
public function testEmptyArrayIsValid(): void
{
$this->validator->validate([], new \Chill\MainBundle\Validation\Constraint\UserGroupDoNotExclude());
$this->assertNoViolation();
}
public function testMixedUserGroupAndUsersIsValid(): void
{
$this->validator->validate(
[new User(), new UserGroup()],
new \Chill\MainBundle\Validation\Constraint\UserGroupDoNotExclude()
);
$this->assertNoViolation();
}
public function testDifferentExcludeKeysIsValid(): void
{
$this->validator->validate(
[(new UserGroup())->setExcludeKey('A'), (new UserGroup())->setExcludeKey('B')],
new \Chill\MainBundle\Validation\Constraint\UserGroupDoNotExclude()
);
$this->assertNoViolation();
}
public function testMultipleGroupsWithEmptyExcludeKeyIsValid(): void
{
$this->validator->validate(
[(new UserGroup())->setExcludeKey(''), (new UserGroup())->setExcludeKey('')],
new \Chill\MainBundle\Validation\Constraint\UserGroupDoNotExclude()
);
$this->assertNoViolation();
}
public function testSameExclusionKeyWillRaiseError(): void
{
$this->validator->validate(
[
(new UserGroup())->setExcludeKey('A')->setLabel(['fr' => 'Group 1']),
(new UserGroup())->setExcludeKey('A')->setLabel(['fr' => 'Group 2']),
],
new \Chill\MainBundle\Validation\Constraint\UserGroupDoNotExclude()
);
$this->buildViolation('The groups {{ excluded_groups }} do exclude themselves. Please choose one between them')
->setParameter('excluded_groups', 'Group 1, Group 2')
->setCode('e16c8226-0090-11ef-8560-f7239594db09')
->assertRaised();
}
}

View File

@@ -10,6 +10,31 @@ servers:
components: components:
schemas: schemas:
Collection:
type: object
properties:
count:
type: number
format: u64
pagination:
type: object
properties:
first:
type: number
format: u64
items_per_page:
type: number
format: u64
next:
type: string
format: uri
nullable: true
previous:
type: string
format: uri
nullable: true
more:
type: boolean
EntityWorkflowAttachment: EntityWorkflowAttachment:
type: object type: object
properties: properties:

View File

@@ -130,3 +130,58 @@ filter_order:
Search: Chercher dans la liste Search: Chercher dans la liste
By date: Filtrer par date By date: Filtrer par date
search_box: Filtrer par contenu search_box: Filtrer par contenu
renderbox:
person: "Usager"
birthday:
man: "Né le"
woman: "Née le"
neutral: "Né·e le"
unknown: "Né·e le"
deathdate: "Date de décès"
household_without_address: "Le ménage de l'usager est sans adresse"
no_data: "Aucune information renseignée"
type:
thirdparty: "Tiers"
person: "Usager"
holder: "Titulaire"
years_old: >-
{n, plural,
=0 {0 an}
one {1 an}
other {# ans}
}
residential_address: "Adresse de résidence"
located_at: "réside chez"
household_number: "Ménage n°{number}"
current_members: "Membres actuels"
no_current_address: "Sans adresse actuellement"
new_household: "Nouveau ménage"
no_members_yet: "Aucun membre actuellement"
pick_entity:
add: "Ajouter"
modal_title: >-
{count, plural,
one {Indiquer un}
other {Ajouter des}
}
user: >-
{count, plural,
one {Utilisateur}
other {Utilisateurs}
}
user_group: >-
{count, plural,
one {Groupe d'utilisateur}
other {Groupes d'utilisateurs}
}
person: >-
{count, plural,
one {Usager}
other {Usagers}
}
thirdparty: >-
{count, plural,
one {Tiers}
other {Tiers}
}

View File

@@ -941,3 +941,34 @@ multiselect:
editor: editor:
switch_to_simple: Éditeur simple switch_to_simple: Éditeur simple
switch_to_complex: Éditeur riche switch_to_complex: Éditeur riche
action:
actions: Actions
show: Voir
edit: Modifier
create: Créer
remove: Enlever
delete: Supprimer
save: Enregistrer
valid: Valider
valid_and_see: Valider et voir
add: Ajouter
show_modal: Ouvrir une modale
ok: OK
cancel: Annuler
close: Fermer
back: Retour
check_all: cocher tout
reset: réinitialiser
redirect:
person: Quitter la page et ouvrir la fiche de l'usager
thirdparty: Quitter la page et voir le tiers
refresh: Rafraîchir
addContact: Ajouter un contact
nav:
next: "Suivant"
previous: "Précédent"
top: "Haut"
bottom: "Bas"

View File

@@ -21,6 +21,8 @@ use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
use libphonenumber\PhoneNumber;
use libphonenumber\PhoneNumberFormat;
use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\Security;
final readonly class PersonACLAwareRepository implements PersonACLAwareRepositoryInterface final readonly class PersonACLAwareRepository implements PersonACLAwareRepositoryInterface
@@ -298,4 +300,27 @@ final readonly class PersonACLAwareRepository implements PersonACLAwareRepositor
\array_map(static fn (Center $c) => $c->getId(), $authorizedCenters) \array_map(static fn (Center $c) => $c->getId(), $authorizedCenters)
); );
} }
public function findByPhone(PhoneNumber $phoneNumber, int $start = 0, int $limit = 20): array
{
$authorizedCenters = $this->authorizationHelper
->getReachableCenters($this->security->getUser(), PersonVoter::SEE);
if ([] === $authorizedCenters) {
return [];
}
$util = \libphonenumber\PhoneNumberUtil::getInstance();
return $this->em->createQuery(
'SELECT p FROM '.Person::class.' p LEFT JOIN p.otherPhoneNumbers opn JOIN p.centerCurrent pcc '.
'WHERE (p.phonenumber LIKE :phone OR p.mobilenumber LIKE :phone OR opn.phonenumber LIKE :phone) '.
'AND pcc.center IN (:centers)'
)
->setMaxResults($limit)
->setFirstResult($start)
->setParameter('phone', $util->format($phoneNumber, PhoneNumberFormat::E164))
->setParameter('centers', $authorizedCenters)
->getResult();
}
} }

View File

@@ -13,6 +13,7 @@ namespace Chill\PersonBundle\Repository;
use Chill\MainBundle\Search\SearchApiQuery; use Chill\MainBundle\Search\SearchApiQuery;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use libphonenumber\PhoneNumber;
interface PersonACLAwareRepositoryInterface interface PersonACLAwareRepositoryInterface
{ {
@@ -60,4 +61,13 @@ interface PersonACLAwareRepositoryInterface
?string $phonenumber = null, ?string $phonenumber = null,
?string $city = null, ?string $city = null,
): array; ): array;
/**
* @return list<Person>
*/
public function findByPhone(
PhoneNumber $phoneNumber,
int $start = 0,
int $limit = 20,
): array;
} }

View File

@@ -12,10 +12,12 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Repository; namespace Chill\PersonBundle\Repository;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\PersonPhone;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository; use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ObjectRepository; use Doctrine\Persistence\ObjectRepository;
use libphonenumber\PhoneNumber;
class PersonRepository implements ObjectRepository class PersonRepository implements ObjectRepository
{ {
@@ -29,6 +31,8 @@ class PersonRepository implements ObjectRepository
/** /**
* @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NoResultException
* @throws \Doctrine\ORM\NonUniqueResultException * @throws \Doctrine\ORM\NonUniqueResultException
*
* @deprecated
*/ */
public function countByPhone( public function countByPhone(
string $phonenumber, string $phonenumber,
@@ -71,6 +75,8 @@ class PersonRepository implements ObjectRepository
/** /**
* @throws \Exception * @throws \Exception
*
* @deprecated Use @see{self::findByPhoneNumber} or use a dedicated method in PersonACLAwareRepository
*/ */
public function findByPhone( public function findByPhone(
string $phonenumber, string $phonenumber,
@@ -91,6 +97,25 @@ class PersonRepository implements ObjectRepository
return $qb->getQuery()->getResult(); return $qb->getQuery()->getResult();
} }
/**
* Find a person which is associated to the given phonenumber, without restrictions
* on any.
*
* @return list<Person>
*/
public function findByPhoneNumber(PhoneNumber $phoneNumber, int $firstResult = 0, int $maxResults = 50): array
{
$qb = $this->repository->createQueryBuilder('p');
$qb->select('p');
$this->searchByPhoneNumbers($qb, $phoneNumber);
$qb->setFirstResult($firstResult)
->setMaxResults($maxResults);
return $qb->getQuery()->getResult();
}
public function findOneBy(array $criteria) public function findOneBy(array $criteria)
{ {
return $this->repository->findOneBy($criteria); return $this->repository->findOneBy($criteria);
@@ -109,6 +134,20 @@ class PersonRepository implements ObjectRepository
} }
} }
private function searchByPhoneNumbers(QueryBuilder $qb, PhoneNumber $phoneNumber): void
{
$qb->setParameter('number', $phoneNumber, 'phone_number');
$orX = $qb->expr()->orX();
$orX->add($qb->expr()->eq('p.mobilenumber', ':number'));
$orX->add($qb->expr()->eq('p.phonenumber', ':number'));
$orX->add(
$qb->expr()->exists('SELECT 1 FROM '.PersonPhone::class.' k WHERE k.phonenumber = :number AND k.person = p')
);
$qb->andWhere($orX);
}
/** /**
* @throws \Exception * @throws \Exception
*/ */

View File

@@ -27,9 +27,7 @@ document.addEventListener("DOMContentLoaded", () => {
throw "accompanying period id not found"; throw "accompanying period id not found";
} }
const accompanyingPeriodId = Number.parseInt( const accompanyingPeriodId = Number.parseInt(accompanyingPeriodIdAsString);
accompanyingPeriodIdAsString,
);
const app = createApp({ const app = createApp({
template: template:

View File

@@ -1,11 +1,13 @@
import { import {
Address, Address,
Scope,
Center, Center,
Civility, Civility,
DateTime, DateTime,
User, User,
UserGroup,
Household,
WorkflowAvailable, WorkflowAvailable,
Scope,
Job, Job,
PrivateCommentEmbeddable, PrivateCommentEmbeddable,
} from "ChillMainAssets/types"; } from "ChillMainAssets/types";
@@ -13,6 +15,11 @@ import { StoredObject } from "ChillDocStoreAssets/types";
import { Thirdparty } from "../../../ChillThirdPartyBundle/Resources/public/types"; import { Thirdparty } from "../../../ChillThirdPartyBundle/Resources/public/types";
import { Calendar } from "../../../ChillCalendarBundle/Resources/public/types"; import { Calendar } from "../../../ChillCalendarBundle/Resources/public/types";
export interface AltName {
label: string;
key: string;
}
export interface Person { export interface Person {
id: number; id: number;
type: "person"; type: "person";
@@ -20,6 +27,8 @@ export interface Person {
textAge: string; textAge: string;
firstName: string; firstName: string;
lastName: string; lastName: string;
altNames: AltName[];
suffixText: string;
current_household_address: Address | null; current_household_address: Address | null;
birthdate: DateTime | null; birthdate: DateTime | null;
deathdate: DateTime | null; deathdate: DateTime | null;
@@ -70,19 +79,6 @@ export interface AccompanyingPeriod {
| "DRAFT"; | "DRAFT";
} }
export interface AccompanyingPeriodWorkEvaluationDocument {
id: number;
type: "accompanying_period_work_evaluation_document";
storedObject: StoredObject;
title: string;
createdAt: DateTime | null;
createdBy: User | null;
updatedAt: DateTime | null;
updatedBy: User | null;
workflows_availables: WorkflowAvailable[];
workflows: object[];
}
export interface AccompanyingPeriodWork { export interface AccompanyingPeriodWork {
id: number; id: number;
accompanyingPeriod?: AccompanyingPeriod; accompanyingPeriod?: AccompanyingPeriod;
@@ -107,7 +103,7 @@ export interface AccompanyingPeriodWork {
version: number; version: number;
} }
interface SocialAction { export interface SocialAction {
id: number; id: number;
parent?: SocialAction | null; parent?: SocialAction | null;
children: SocialAction[]; children: SocialAction[];
@@ -251,3 +247,83 @@ export interface AccompanyingPeriodWorkReferrerHistory {
createdBy: User; createdBy: User;
updatedBy: User | null; updatedBy: User | null;
} }
export interface AccompanyingPeriodWorkEvaluationDocument {
id: number;
type: "accompanying_period_work_evaluation_document";
storedObject: StoredObject;
title: string;
createdAt: DateTime | null;
createdBy: User | null;
updatedAt: DateTime | null;
updatedBy: User | null;
workflows_availables: WorkflowAvailable[];
workflows: object[];
}
export type EntityType =
| "user_group"
| "user"
| "person"
| "thirdparty"
| "household";
export type Entities = (UserGroup | User | Person | Thirdparty | Household) & {
address?: Address | null;
kind?: string;
text?: string;
profession?: string;
};
export type EntitiesOrMe = "me" | Entities;
export type AddPersonResult = Entities & {
parent?: Entities | null;
};
export interface Suggestion {
key: string;
relevance: number;
result: AddPersonResult;
}
export interface SearchPagination {
first: number;
items_per_page: number;
next: number | null;
previous: number | null;
more: boolean;
}
export interface Search {
count: number;
pagination: SearchPagination;
results: Suggestion[];
}
export interface SearchOptions {
uniq: boolean;
type: string[];
priority: number | null;
button: {
size: string;
class: string;
type: string;
display: string;
};
}
export class MakeFetchException extends Error {
sta: number;
txt: string;
violations: unknown | null;
constructor(txt: string, sta: number, violations: unknown | null = null) {
super(txt);
this.name = "ValidationException";
this.sta = sta;
this.txt = txt;
this.violations = violations;
Object.setPrototypeOf(this, MakeFetchException.prototype);
}
}

View File

@@ -26,10 +26,7 @@
/> />
</div> </div>
<div <div v-if="!isAdminLocationValid" class="alert alert-warning to-confirm">
v-if="!isAdminLocationValid"
class="alert alert-warning to-confirm"
>
{{ $t("admin_location.not_valid") }} {{ $t("admin_location.not_valid") }}
</div> </div>
</div> </div>
@@ -69,9 +66,7 @@ export default {
locationCategories: response.filter( locationCategories: response.filter(
(o) => o.locationType.id === id, (o) => o.locationType.id === id,
)[0].locationType.title.fr, )[0].locationType.title.fr,
locations: response.filter( locations: response.filter((o) => o.locationType.id === id),
(o) => o.locationType.id === id,
),
}); });
} }
this.options = results; this.options = results;
@@ -81,10 +76,7 @@ export default {
this.$store this.$store
.dispatch("updateAdminLocation", value) .dispatch("updateAdminLocation", value)
.catch(({ name, violations }) => { .catch(({ name, violations }) => {
if ( if (name === "ValidationException" || name === "AccessException") {
name === "ValidationException" ||
name === "AccessException"
) {
violations.forEach((violation) => violations.forEach((violation) =>
this.$toast.open({ message: violation }), this.$toast.open({ message: violation }),
); );

View File

@@ -29,9 +29,7 @@
</span> </span>
</span> </span>
<span <span
v-else-if=" v-else-if="accompanyingCourse.step === 'CONFIRMED_INACTIVE_SHORT'"
accompanyingCourse.step === 'CONFIRMED_INACTIVE_SHORT'
"
class="d-md-block mb-md-3" class="d-md-block mb-md-3"
> >
<span class="badge bg-chill-yellow text-primary"> <span class="badge bg-chill-yellow text-primary">
@@ -39,9 +37,7 @@
</span> </span>
</span> </span>
<span <span
v-else-if=" v-else-if="accompanyingCourse.step === 'CONFIRMED_INACTIVE_LONG'"
accompanyingCourse.step === 'CONFIRMED_INACTIVE_LONG'
"
class="d-md-block mb-md-3" class="d-md-block mb-md-3"
> >
<span class="badge bg-chill-pink"> <span class="badge bg-chill-pink">
@@ -52,25 +48,15 @@
<span class="d-md-block ms-3 ms-md-0"> <span class="d-md-block ms-3 ms-md-0">
<i <i
>{{ $t("course.open_at") >{{ $t("course.open_at")
}}{{ }}{{ $d(accompanyingCourse.openingDate.datetime, "text") }}</i
$d(accompanyingCourse.openingDate.datetime, "text")
}}</i
> >
</span> </span>
<span <span v-if="accompanyingCourse.user" class="d-md-block ms-3 ms-md-0">
v-if="accompanyingCourse.user" <span class="item-key">{{ $t("course.referrer") }}:</span>&nbsp;
class="d-md-block ms-3 ms-md-0"
>
<span class="item-key">{{ $t("course.referrer") }}:</span
>&nbsp;
<b>{{ accompanyingCourse.user.text }}</b> <b>{{ accompanyingCourse.user.text }}</b>
<template v-if="accompanyingCourse.user.isAbsent"> <template v-if="accompanyingCourse.user.isAbsent">
&nbsp; &nbsp;
<span <span class="badge bg-danger rounded-pill" title="Absent">A</span>
class="badge bg-danger rounded-pill"
title="Absent"
>A</span
>
</template> </template>
</span> </span>
</span> </span>
@@ -82,19 +68,12 @@
<span class="d-md-block"> <span class="d-md-block">
<span class="d-md-block ms-3 ms-md-0"> <span class="d-md-block ms-3 ms-md-0">
<i <i
>{{ >{{ $d(accompanyingCourse.openingDate.datetime, "text") }}
$d(accompanyingCourse.openingDate.datetime, "text")
}}
- -
{{ {{ $d(accompanyingCourse.closingDate.datetime, "text") }}</i
$d(accompanyingCourse.closingDate.datetime, "text")
}}</i
> >
</span> </span>
<span <span v-if="accompanyingCourse.user" class="d-md-block ms-3 ms-md-0">
v-if="accompanyingCourse.user"
class="d-md-block ms-3 ms-md-0"
>
<span class="item-key">{{ $t("course.referrer") }}:</span> <span class="item-key">{{ $t("course.referrer") }}:</span>
<b>{{ accompanyingCourse.user.text }}</b> <b>{{ accompanyingCourse.user.text }}</b>
</span> </span>
@@ -102,9 +81,7 @@
</span> </span>
</teleport> </teleport>
<teleport <teleport to="#header-accompanying_course-name #persons-associated-shortlist">
to="#header-accompanying_course-name #persons-associated-shortlist"
>
<persons-associated <persons-associated
:accompanyingCourse="accompanyingCourse" :accompanyingCourse="accompanyingCourse"
:shortlist="true" :shortlist="true"
@@ -119,9 +96,7 @@
/> />
</teleport> </teleport>
<teleport <teleport to="#header-accompanying_course-details #banner-persons-associated">
to="#header-accompanying_course-details #banner-persons-associated"
>
<persons-associated <persons-associated
:accompanying-course="accompanyingCourse" :accompanying-course="accompanyingCourse"
:shortlist="false" :shortlist="false"

View File

@@ -97,9 +97,7 @@ export default {
if (!households.has(person.current_household_id || -1)) { if (!households.has(person.current_household_id || -1)) {
households.set(person.current_household_id || -1, []); households.set(person.current_household_id || -1, []);
} }
households households.get(person.current_household_id || -1).push(person);
.get(person.current_household_id || -1)
.push(person);
}); });
return households; return households;

Some files were not shown because too many files have changed in this diff Show More