mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-09-12 09:44:58 +00:00
Compare commits
71 Commits
v3.10.2
...
321-text-e
Author | SHA1 | Date | |
---|---|---|---|
b5c9e65986
|
|||
8b2af35e97
|
|||
dc44c46667 | |||
ba571c1a69 | |||
6a364705f2 | |||
b6d454691a | |||
6d7a6932a9 | |||
|
2faf194b15 | ||
f207599d86 | |||
b0959f8cc5 | |||
4c5dee5f0a | |||
f6c98aa0d5 | |||
6d13d184d5 | |||
af36eccfaf | |||
483a20a43f | |||
6d8e2ad825 | |||
86388a63a8 | |||
|
5ea55ebfe5 | ||
f97dc8f931 | |||
|
a9c3aab528 | ||
1181377bd6 | |||
|
2275b7c560 | ||
4a8d298ae5 | |||
3e7f03d331
|
|||
b830952b9e
|
|||
ad17313c61 | |||
620515ad15
|
|||
50c377ee22 | |||
cc7e7a90ee | |||
1d4ef19051
|
|||
8337a724d1
|
|||
8ca377d5d4 | |||
224e0bae43 | |||
3aa4fac80d | |||
|
a7517eb647 | ||
e278e636e0 | |||
|
40e373a9c7 | ||
1c1f418b18 | |||
bf0e14b43a | |||
203a098054
|
|||
d58acff541
|
|||
5858e05a42
|
|||
b9b4fafe14
|
|||
fe6949ea26 | |||
8a444a12f4 | |||
2dcce7b826 | |||
dcd1777a70 | |||
a6eb28175a | |||
7d78512823 | |||
d0cd4792d6 | |||
6d196ead94 | |||
4047d5fd5b | |||
9aac80d834 | |||
7560dc57c6 | |||
10314845f6 | |||
9b84bc4d69 | |||
a2fcf039be | |||
b4d887a372 | |||
0aaa7122da | |||
1bc7f85874 | |||
1d2fd000aa | |||
506df432b0 | |||
c32c18b0e2 | |||
321d569ee9 | |||
cd40eb3932 | |||
f0f2531fa3 | |||
183a220e7b | |||
9df127a82c | |||
04a1412562 | |||
3aef0a185e | |||
578bce31b9 |
6
.changes/unreleased/DX-20250430-144550.yaml
Normal file
6
.changes/unreleased/DX-20250430-144550.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: DX
|
||||||
|
body: Remove dead code for wopi-link module
|
||||||
|
time: 2025-04-30T14:45:50.406111606+02:00
|
||||||
|
custom:
|
||||||
|
Issue: "352"
|
||||||
|
SchemaChange: No schema change
|
7
.changes/unreleased/Feature-20250424-142211.yaml
Normal file
7
.changes/unreleased/Feature-20250424-142211.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
kind: Feature
|
||||||
|
body: Add the document file name to the document title when a user upload a document,
|
||||||
|
unless there is already a document title.
|
||||||
|
time: 2025-04-24T14:22:11.800975422+02:00
|
||||||
|
custom:
|
||||||
|
Issue: "377"
|
||||||
|
SchemaChange: No schema change
|
6
.changes/unreleased/Feature-20250520-095628.yaml
Normal file
6
.changes/unreleased/Feature-20250520-095628.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Feature
|
||||||
|
body: Add desactivation date for social action and issue csv export
|
||||||
|
time: 2025-05-20T09:56:28.108941934+02:00
|
||||||
|
custom:
|
||||||
|
Issue: ""
|
||||||
|
SchemaChange: No schema change
|
7
.changes/unreleased/Fixed-20250424-133943.yaml
Normal file
7
.changes/unreleased/Fixed-20250424-133943.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: trying to prevent bug of typeerror in doc-history + improved display of document
|
||||||
|
history
|
||||||
|
time: 2025-04-24T13:39:43.878468232+02:00
|
||||||
|
custom:
|
||||||
|
Issue: "376"
|
||||||
|
SchemaChange: No schema change
|
7
.changes/unreleased/Fixed-20250424-163746.yaml
Normal file
7
.changes/unreleased/Fixed-20250424-163746.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: Display previous participation in acc course work even if the person has left
|
||||||
|
the acc course
|
||||||
|
time: 2025-04-24T16:37:46.970203594+02:00
|
||||||
|
custom:
|
||||||
|
Issue: "381"
|
||||||
|
SchemaChange: No schema change
|
6
.changes/unreleased/Fixed-20250505-102715.yaml
Normal file
6
.changes/unreleased/Fixed-20250505-102715.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: Fix display of text in calendar events
|
||||||
|
time: 2025-05-05T10:27:15.461493066+02:00
|
||||||
|
custom:
|
||||||
|
Issue: "372"
|
||||||
|
SchemaChange: No schema change
|
6
.changes/unreleased/Fixed-20250514-145339.yaml
Normal file
6
.changes/unreleased/Fixed-20250514-145339.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: Add missing translation for user_group.no_user_groups
|
||||||
|
time: 2025-05-14T14:53:39.53927329+02:00
|
||||||
|
custom:
|
||||||
|
Issue: ""
|
||||||
|
SchemaChange: No schema change
|
6
.changes/unreleased/UX-20250423-172624.yaml
Normal file
6
.changes/unreleased/UX-20250423-172624.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
kind: UX
|
||||||
|
body: Remove default filter in_progress for the page 'my tasks'; Allows for new tasks to be displayed upon opening of the page
|
||||||
|
time: 2025-04-23T17:26:24.45777387+02:00
|
||||||
|
custom:
|
||||||
|
Issue: "374"
|
||||||
|
SchemaChange: No schema change
|
3
.changes/v3.10.3.md
Normal file
3
.changes/v3.10.3.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
## v3.10.3 - 2025-03-18
|
||||||
|
### DX
|
||||||
|
* Eslint fixes
|
19
.changes/v3.11.0.md
Normal file
19
.changes/v3.11.0.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
## v3.11.0 - 2025-04-17
|
||||||
|
### Feature
|
||||||
|
* ([#365](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/365)) Add counters of actions and activities, with 2 boxes to (1) show the number of active actions on total actions and (2) show the number of activities in a accompanying period, and pills in menus for showing the number of active actions and the number of activities.
|
||||||
|
* ([#364](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/364)) Added a second phone number "telephone2" to the thirdParty entity. Adapted twig templates and vuejs apps to handle this phone number
|
||||||
|
|
||||||
|
**Schema Change**: Add columns or tables
|
||||||
|
* Signature: add a button to go directly to the signature zone, even if there is only one
|
||||||
|
### Fixed
|
||||||
|
* Fixed wrong translations in the on-the-fly for creation of thirdParty
|
||||||
|
* Fixed update of phone number in on-the-fly edition of thirdParty
|
||||||
|
* Fixed closing of modal when editing thirdParty in accompanying course works
|
||||||
|
* Shorten the delay between two execution of AccompanyingPeriodStepChangeCronjob, to ensure at least one execution in a day
|
||||||
|
* ([#102](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/102)) Fix display of title in document list
|
||||||
|
* When cleaning the old stored object versions, do not throw an error if the stored object is not found on disk
|
||||||
|
* Add consistent log prefix and key to logs when stale workflows are automatically canceled
|
||||||
|
* ([#380](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/380)) Remove the "not null" validation constraint on recently added properties on HouseholdComposition
|
||||||
|
|
||||||
|
### DX
|
||||||
|
* Add new chill-col style for displaying title and aside in a flex table
|
@@ -6,6 +6,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
|
|||||||
and is generated by [Changie](https://github.com/miniscruff/changie).
|
and is generated by [Changie](https://github.com/miniscruff/changie).
|
||||||
|
|
||||||
|
|
||||||
|
## v3.10.3 - 2025-03-18
|
||||||
|
### DX
|
||||||
|
* Eslint fixes
|
||||||
|
|
||||||
## v3.10.2 - 2025-03-17
|
## v3.10.2 - 2025-03-17
|
||||||
### Fixed
|
### Fixed
|
||||||
* Replace a ts-expect-error with a ts-ignore
|
* Replace a ts-expect-error with a ts-ignore
|
||||||
|
@@ -220,6 +220,7 @@ framework:
|
|||||||
- attenteModification
|
- attenteModification
|
||||||
- attenteMiseEnForme
|
- attenteMiseEnForme
|
||||||
- attenteValidationMiseEnForme
|
- attenteValidationMiseEnForme
|
||||||
|
- attenteSignature
|
||||||
- attenteVisa
|
- attenteVisa
|
||||||
- postSignature
|
- postSignature
|
||||||
- attenteTraitement
|
- attenteTraitement
|
||||||
|
@@ -34,6 +34,7 @@ export default ts.config(
|
|||||||
// override/add rules settings here, such as:
|
// override/add rules settings here, such as:
|
||||||
"vue/multi-word-component-names": "off",
|
"vue/multi-word-component-names": "off",
|
||||||
"@typescript-eslint/no-require-imports": "off",
|
"@typescript-eslint/no-require-imports": "off",
|
||||||
|
"@typescript-eslint/ban-ts-comment": "off"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
"@hotwired/stimulus": "^3.0.0",
|
"@hotwired/stimulus": "^3.0.0",
|
||||||
"@luminateone/eslint-baseline": "^1.0.9",
|
"@luminateone/eslint-baseline": "^1.0.9",
|
||||||
"@symfony/stimulus-bridge": "^3.2.0",
|
"@symfony/stimulus-bridge": "^3.2.0",
|
||||||
|
"@symfony/ux-translator": "file:vendor/symfony/ux-translator/assets",
|
||||||
"@symfony/webpack-encore": "^4.1.0",
|
"@symfony/webpack-encore": "^4.1.0",
|
||||||
"@tsconfig/node20": "^20.1.4",
|
"@tsconfig/node20": "^20.1.4",
|
||||||
"@types/dompurify": "^3.0.5",
|
"@types/dompurify": "^3.0.5",
|
||||||
|
@@ -11,6 +11,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\ActivityBundle\Menu;
|
namespace Chill\ActivityBundle\Menu;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
||||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
@@ -23,22 +24,30 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||||||
*/
|
*/
|
||||||
class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
|
class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
|
||||||
{
|
{
|
||||||
public function __construct(protected Security $security, protected TranslatorInterface $translator) {}
|
public function __construct(
|
||||||
|
protected Security $security,
|
||||||
|
protected TranslatorInterface $translator,
|
||||||
|
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||||
{
|
{
|
||||||
$period = $parameters['accompanyingCourse'];
|
$period = $parameters['accompanyingCourse'];
|
||||||
|
|
||||||
|
$activities = $this->managerRegistry->getManager()->getRepository(Activity::class)->findBy(
|
||||||
|
['accompanyingPeriod' => $period]
|
||||||
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
AccompanyingPeriod::STEP_DRAFT !== $period->getStep()
|
AccompanyingPeriod::STEP_DRAFT !== $period->getStep()
|
||||||
&& $this->security->isGranted(ActivityVoter::SEE, $period)
|
&& $this->security->isGranted(ActivityVoter::SEE, $period)
|
||||||
) {
|
) {
|
||||||
$menu->addChild($this->translator->trans('Activity'), [
|
$menu->addChild($this->translator->trans('Activities'), [
|
||||||
'route' => 'chill_activity_activity_list',
|
'route' => 'chill_activity_activity_list',
|
||||||
'routeParameters' => [
|
'routeParameters' => [
|
||||||
'accompanying_period_id' => $period->getId(),
|
'accompanying_period_id' => $period->getId(),
|
||||||
], ])
|
], ])
|
||||||
->setExtras(['order' => 40]);
|
->setExtras(['order' => 40, 'counter' => count($activities) > 0 ? count($activities) : null]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -11,6 +11,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\ActivityBundle\Menu;
|
namespace Chill\ActivityBundle\Menu;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface;
|
||||||
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
use Chill\ActivityBundle\Security\Authorization\ActivityVoter;
|
||||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
@@ -23,13 +24,20 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||||||
*/
|
*/
|
||||||
final readonly class PersonMenuBuilder implements LocalMenuBuilderInterface
|
final readonly class PersonMenuBuilder implements LocalMenuBuilderInterface
|
||||||
{
|
{
|
||||||
public function __construct(private AuthorizationCheckerInterface $authorizationChecker, private TranslatorInterface $translator) {}
|
public function __construct(
|
||||||
|
private readonly ActivityACLAwareRepositoryInterface $activityACLAwareRepository,
|
||||||
|
private AuthorizationCheckerInterface $authorizationChecker,
|
||||||
|
private TranslatorInterface $translator,
|
||||||
|
) {}
|
||||||
|
|
||||||
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||||
{
|
{
|
||||||
/** @var Person $person */
|
/** @var Person $person */
|
||||||
$person = $parameters['person'];
|
$person = $parameters['person'];
|
||||||
|
|
||||||
|
|
||||||
|
$count = $this->activityACLAwareRepository->countByPerson($person, ActivityVoter::SEE);
|
||||||
|
|
||||||
if ($this->authorizationChecker->isGranted(ActivityVoter::SEE, $person)) {
|
if ($this->authorizationChecker->isGranted(ActivityVoter::SEE, $person)) {
|
||||||
$menu->addChild(
|
$menu->addChild(
|
||||||
$this->translator->trans('Activities'),
|
$this->translator->trans('Activities'),
|
||||||
@@ -38,7 +46,7 @@ final readonly class PersonMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
'routeParameters' => ['person_id' => $person->getId()],
|
'routeParameters' => ['person_id' => $person->getId()],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
->setExtra('order', 201);
|
->setExtras(['order' => 201, 'counter' => $count > 0 ? $count : null]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -120,3 +120,34 @@ li.document-list-item {
|
|||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge-activity-type-simple {
|
||||||
|
@extend .badge;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0.2rem 0;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0.5rem;
|
||||||
|
|
||||||
|
border-left: 20px groove #9acd32;
|
||||||
|
border-radius: $badge-border-radius;
|
||||||
|
|
||||||
|
color: black;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: unset;
|
||||||
|
max-width: 100%;
|
||||||
|
background-color: $gray-100;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
text-indent: 5px hanging;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
margin-right: 3px;
|
||||||
|
position: relative;
|
||||||
|
left: -0.5px;
|
||||||
|
font-family: ForkAwesome;
|
||||||
|
content: '\f04b';
|
||||||
|
color: #9acd32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -11,7 +11,7 @@ import Location from "./components/Location.vue";
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
props: ["hasSocialIssues", "hasLocation", "hasPerson"],
|
props: ["hasSocialIssues", "hasLocation", "hasPerson", "isSimpleEditor"],
|
||||||
components: {
|
components: {
|
||||||
ConcernedGroups,
|
ConcernedGroups,
|
||||||
SocialIssuesAcc,
|
SocialIssuesAcc,
|
||||||
|
@@ -14,18 +14,21 @@ const i18n = _createI18n(activityMessages);
|
|||||||
const hasSocialIssues = document.querySelector("#social-issues-acc") !== null;
|
const hasSocialIssues = document.querySelector("#social-issues-acc") !== null;
|
||||||
const hasLocation = document.querySelector("#location") !== null;
|
const hasLocation = document.querySelector("#location") !== null;
|
||||||
const hasPerson = document.querySelector("#add-persons") !== null;
|
const hasPerson = document.querySelector("#add-persons") !== null;
|
||||||
|
const isSimpleEditor = true;
|
||||||
|
|
||||||
const app = createApp({
|
const app = createApp({
|
||||||
template: `<app
|
template: `<app
|
||||||
:hasSocialIssues="hasSocialIssues"
|
:hasSocialIssues="hasSocialIssues"
|
||||||
:hasLocation="hasLocation"
|
:hasLocation="hasLocation"
|
||||||
:hasPerson="hasPerson"
|
:hasPerson="hasPerson"
|
||||||
|
:isSimpleEditor = "isSimpleEditor"
|
||||||
></app>`,
|
></app>`,
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
hasSocialIssues,
|
hasSocialIssues,
|
||||||
hasLocation,
|
hasLocation,
|
||||||
hasPerson,
|
hasPerson,
|
||||||
|
isSimpleEditor
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@@ -126,4 +126,4 @@
|
|||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ encore_entry_link_tags('mod_pickentity_type') }}
|
{{ encore_entry_link_tags('mod_pickentity_type') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -13,44 +13,44 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="item-row">
|
<div class="item-row">
|
||||||
<div class="item-col" style="width: unset">
|
<div class="item-two-col-grid">
|
||||||
{% if document.isPending %}
|
<div class="title">
|
||||||
<div class="badge text-bg-info" data-docgen-is-pending="{{ document.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
|
{% if document.isPending %}
|
||||||
{% elseif document.isFailure %}
|
<div class="badge text-bg-info" data-docgen-is-pending="{{ document.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
|
||||||
<div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
|
{% elseif document.isFailure %}
|
||||||
{% endif %}
|
<div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
{% if activity.accompanyingPeriod is not null and context == 'person' %}
|
|
||||||
<span class="badge bg-primary">
|
|
||||||
<i class="fa fa-random"></i> {{ activity.accompanyingPeriod.id }}
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="badge-activity-type">
|
|
||||||
<span class="title_label"></span>
|
<div>
|
||||||
<span class="title_action">
|
<div>
|
||||||
{{ activity.type.name | localize_translatable_string }}
|
<div class="badge-activity-type-simple">
|
||||||
|
{{ activity.type.name | localize_translatable_string }}
|
||||||
|
</div>
|
||||||
{% if activity.emergency %}
|
{% if activity.emergency %}
|
||||||
<span class="badge bg-danger rounded-pill fs-6 float-end">{{ 'Emergency'|trans|upper }}</span>
|
<span class="badge bg-danger rounded-pill fs-6 float-end">{{ 'Emergency'|trans|upper }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="denomination h2">
|
||||||
<div class="denomination h2">
|
{{ document.title|chill_print_or_message("No title") }}
|
||||||
{{ document.title|chill_print_or_message("No title") }}
|
|
||||||
</div>
|
|
||||||
{% if document.hasTemplate %}
|
|
||||||
<div>
|
|
||||||
<p>{{ document.template.name|localize_translatable_string }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% if document.hasTemplate %}
|
||||||
</div>
|
<div>
|
||||||
|
<p>{{ document.template.name|localize_translatable_string }}</p>
|
||||||
<div class="item-col">
|
</div>
|
||||||
<div class="container">
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="aside">
|
||||||
<div class="dates row text-end">
|
<div class="dates row text-end">
|
||||||
<span>{{ document.createdAt|format_date('short') }}</span>
|
<span>{{ document.createdAt|format_date('short') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
{% if activity.accompanyingPeriod is not null and context == 'person' %}
|
||||||
|
<div class="text-end">
|
||||||
|
<span class="badge bg-primary">
|
||||||
|
<i class="fa fa-random"></i> {{ activity.accompanyingPeriod.id }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
@import '~ChillPersonAssets/chill/scss/mixins.scss';
|
|
||||||
@import '~ChillMainAssets/module/bootstrap/shared';
|
@import '~ChillMainAssets/module/bootstrap/shared';
|
||||||
|
@import '~ChillPersonAssets/chill/scss/mixins.scss';
|
||||||
|
@import 'bootstrap/scss/_badge.scss';
|
||||||
|
|
||||||
.badge-calendar {
|
.badge-calendar {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -23,3 +24,35 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge-calendar-simple {
|
||||||
|
@extend .badge;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0.2rem 0;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0.5rem;
|
||||||
|
|
||||||
|
border-left: 20px groove $chill-l-gray;
|
||||||
|
border-radius: $badge-border-radius;
|
||||||
|
|
||||||
|
max-width: 100%;
|
||||||
|
background-color: $gray-100;
|
||||||
|
|
||||||
|
color: black;
|
||||||
|
font-weight: normal;
|
||||||
|
overflow: hidden;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: unset;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
text-indent: 5px hanging;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
margin-right: 3px;
|
||||||
|
position: relative;
|
||||||
|
left: -0.5px;
|
||||||
|
font-family: ForkAwesome;
|
||||||
|
content: '\f04b';
|
||||||
|
color: $chill-l-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@ div.calendar-list {
|
|||||||
}
|
}
|
||||||
|
|
||||||
& > a.calendar-list__global {
|
& > a.calendar-list__global {
|
||||||
display: inline-block;;
|
display: inline-block;
|
||||||
padding: 0.2rem;
|
padding: 0.2rem;
|
||||||
min-width: 2rem;
|
min-width: 2rem;
|
||||||
border: 1px solid var(--bs-chill-blue);
|
border: 1px solid var(--bs-chill-blue);
|
||||||
|
@@ -96,23 +96,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<FullCalendar :options="calendarOptions" ref="calendarRef">
|
<FullCalendar :options="calendarOptions" ref="calendarRef">
|
||||||
<template v-slot:eventContent="{ arg }: { arg: { event: EventApi } }">
|
<template v-slot:eventContent="{ event }">
|
||||||
<span :class="eventClasses(arg.event)">
|
<span :class="eventClasses(event)">
|
||||||
<b v-if="arg.event.extendedProps.is === 'remote'">{{
|
<b v-if="event.extendedProps.is === 'remote'">{{
|
||||||
arg.event.title
|
event.title
|
||||||
}}</b>
|
}}</b>
|
||||||
<b v-else-if="arg.event.extendedProps.is === 'range'"
|
<b v-else-if="event.extendedProps.is === 'range'"
|
||||||
>{{ arg.event.startStr }} -
|
>{{ formatDate(event.startStr) }} -
|
||||||
{{ arg.event.extendedProps.locationName }}</b
|
{{ event.extendedProps.locationName }}</b
|
||||||
>
|
>
|
||||||
<b v-else-if="arg.event.extendedProps.is === 'local'">{{
|
<b v-else-if="event.extendedProps.is === 'local'">{{
|
||||||
arg.event.title
|
event.title
|
||||||
}}</b>
|
}}</b>
|
||||||
<b v-else>no 'is'</b>
|
<b v-else>no 'is'</b>
|
||||||
<a
|
<a
|
||||||
v-if="arg.event.extendedProps.is === 'range'"
|
v-if="event.extendedProps.is === 'range'"
|
||||||
class="fa fa-fw fa-times delete"
|
class="fa fa-fw fa-times delete"
|
||||||
@click.prevent="onClickDelete(arg.event)"
|
@click.prevent="onClickDelete(event)"
|
||||||
>
|
>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
@@ -221,13 +221,12 @@ import type {
|
|||||||
DatesSetArg,
|
DatesSetArg,
|
||||||
EventInput,
|
EventInput,
|
||||||
} from "@fullcalendar/core";
|
} from "@fullcalendar/core";
|
||||||
import { reactive, computed, ref, onMounted } from "vue";
|
import { computed, ref, onMounted } from "vue";
|
||||||
import { useStore } from "vuex";
|
import { useStore } from "vuex";
|
||||||
import { key } from "./store";
|
import { key } from "./store";
|
||||||
import FullCalendar from "@fullcalendar/vue3";
|
import FullCalendar from "@fullcalendar/vue3";
|
||||||
import frLocale from "@fullcalendar/core/locales/fr";
|
import frLocale from "@fullcalendar/core/locales/fr";
|
||||||
import interactionPlugin, {
|
import interactionPlugin, {
|
||||||
DropArg,
|
|
||||||
EventResizeDoneArg,
|
EventResizeDoneArg,
|
||||||
} from "@fullcalendar/interaction";
|
} from "@fullcalendar/interaction";
|
||||||
import timeGridPlugin from "@fullcalendar/timegrid";
|
import timeGridPlugin from "@fullcalendar/timegrid";
|
||||||
@@ -237,19 +236,13 @@ import {
|
|||||||
EventDropArg,
|
EventDropArg,
|
||||||
EventClickArg,
|
EventClickArg,
|
||||||
} from "@fullcalendar/core";
|
} from "@fullcalendar/core";
|
||||||
import {
|
import { dateToISO, ISOToDate } from "ChillMainAssets/chill/js/date";
|
||||||
dateToISO,
|
|
||||||
ISOToDate,
|
|
||||||
} from "../../../../../ChillMainBundle/Resources/public/chill/js/date";
|
|
||||||
import VueMultiselect from "vue-multiselect";
|
import VueMultiselect from "vue-multiselect";
|
||||||
import { Location } from "../../../../../ChillMainBundle/Resources/public/types";
|
import { Location } from "ChillMainAssets/types";
|
||||||
import EditLocation from "./Components/EditLocation.vue";
|
import EditLocation from "./Components/EditLocation.vue";
|
||||||
import { useI18n } from "vue-i18n";
|
|
||||||
|
|
||||||
const store = useStore(key);
|
const store = useStore(key);
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const showWeekends = ref(false);
|
const showWeekends = ref(false);
|
||||||
const slotDuration = ref("00:15:00");
|
const slotDuration = ref("00:15:00");
|
||||||
const slotMinTime = ref("09:00:00");
|
const slotMinTime = ref("09:00:00");
|
||||||
@@ -301,6 +294,11 @@ const nextWeeks = computed((): Weeks[] =>
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const formatDate = (datetime: string) => {
|
||||||
|
console.log(typeof datetime);
|
||||||
|
return ISOToDate(datetime);
|
||||||
|
};
|
||||||
|
|
||||||
const baseOptions = ref<CalendarOptions>({
|
const baseOptions = ref<CalendarOptions>({
|
||||||
locale: frLocale,
|
locale: frLocale,
|
||||||
plugins: [interactionPlugin, timeGridPlugin],
|
plugins: [interactionPlugin, timeGridPlugin],
|
||||||
@@ -353,7 +351,7 @@ const pickedLocation = computed<Location | null>({
|
|||||||
* return the show classes for the event
|
* return the show classes for the event
|
||||||
* @param arg
|
* @param arg
|
||||||
*/
|
*/
|
||||||
const eventClasses = function (arg: EventApi): object {
|
const eventClasses = function (): object {
|
||||||
return { calendarRangeItems: true };
|
return { calendarRangeItems: true };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -431,7 +429,6 @@ function onEventDropOrResize(payload: EventDropArg | EventResizeDoneArg) {
|
|||||||
if (payload.event.extendedProps.is !== "range") {
|
if (payload.event.extendedProps.is !== "range") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const changedEvent = payload.event;
|
|
||||||
|
|
||||||
store.dispatch("calendarRanges/patchRangeTime", {
|
store.dispatch("calendarRanges/patchRangeTime", {
|
||||||
calendarRangeId: payload.event.extendedProps.calendarRangeId,
|
calendarRangeId: payload.event.extendedProps.calendarRangeId,
|
||||||
|
@@ -6,50 +6,48 @@
|
|||||||
|
|
||||||
|
|
||||||
<div class="item-row">
|
<div class="item-row">
|
||||||
<div class="item-col" style="width: unset">
|
<div class="item-two-col-grid">
|
||||||
{% if document.storedObject.isPending %}
|
<div class="title">
|
||||||
<div class="badge text-bg-info" data-docgen-is-pending="{{ document.storedObject.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
|
{% if document.storedObject.isPending %}
|
||||||
{% elseif document.storedObject.isFailure %}
|
<div class="badge text-bg-info" data-docgen-is-pending="{{ document.storedObject.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
|
||||||
<div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
|
{% elseif document.storedObject.isFailure %}
|
||||||
{% endif %}
|
<div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
{% if c.accompanyingPeriod is not null and context == 'person' %}
|
|
||||||
<span class="badge bg-primary">
|
|
||||||
<i class="fa fa-random"></i> {{ c.accompanyingPeriod.id }}
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<span class="badge-calendar">
|
|
||||||
<span class="title_label"></span>
|
|
||||||
<span class="title_action">
|
|
||||||
{{ 'Calendar'|trans }}
|
|
||||||
{% if c.endDate.diff(c.startDate).days >= 1 %}
|
|
||||||
{{ c.startDate|format_datetime('short', 'short') }}
|
|
||||||
- {{ c.endDate|format_datetime('short', 'short') }}
|
|
||||||
{% else %}
|
|
||||||
{{ c.startDate|format_datetime('short', 'short') }}
|
|
||||||
- {{ c.endDate|format_datetime('none', 'short') }}
|
|
||||||
{% endif %}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="denomination h2">
|
|
||||||
{{ document.storedObject.title|chill_print_or_message("No title") }}
|
|
||||||
</div>
|
|
||||||
{% if document.storedObject.hasTemplate %}
|
|
||||||
<div>
|
<div>
|
||||||
<p>{{ document.storedObject.template.name|localize_translatable_string }}</p>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="item-col">
|
<span class="badge-calendar-simple">
|
||||||
<div class="container">
|
{{ 'Calendar'|trans }}
|
||||||
|
{% if c.endDate.diff(c.startDate).days >= 1 %}
|
||||||
|
{{ c.startDate|format_datetime('short', 'short') }}
|
||||||
|
- {{ c.endDate|format_datetime('short', 'short') }}
|
||||||
|
{% else %}
|
||||||
|
{{ c.startDate|format_datetime('short', 'short') }}
|
||||||
|
- {{ c.endDate|format_datetime('none', 'short') }}
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="denomination h2">
|
||||||
|
{{ document.storedObject.title|chill_print_or_message("No title") }}
|
||||||
|
</div>
|
||||||
|
{% if document.storedObject.hasTemplate %}
|
||||||
|
<div>
|
||||||
|
<p>{{ document.storedObject.template.name|localize_translatable_string }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="aside">
|
||||||
<div class="dates row text-end">
|
<div class="dates row text-end">
|
||||||
<span>{{ document.storedObject.createdAt|format_date('short') }}</span>
|
<span>{{ document.storedObject.createdAt|format_date('short') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
{% if c.accompanyingPeriod is not null and context == 'person' %}
|
||||||
|
<div class="text-end">
|
||||||
|
<span class="badge bg-primary">
|
||||||
|
<i class="fa fa-random"></i> {{ c.accompanyingPeriod.id }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -10,6 +10,9 @@ const startApp = (
|
|||||||
collectionEntry: null | HTMLLIElement,
|
collectionEntry: null | HTMLLIElement,
|
||||||
): void => {
|
): void => {
|
||||||
console.log("app started", divElement);
|
console.log("app started", divElement);
|
||||||
|
|
||||||
|
const inputTitle = collectionEntry?.querySelector("input[type='text']");
|
||||||
|
|
||||||
const input_stored_object: HTMLInputElement | null =
|
const input_stored_object: HTMLInputElement | null =
|
||||||
divElement.querySelector("input[data-stored-object]");
|
divElement.querySelector("input[data-stored-object]");
|
||||||
if (null === input_stored_object) {
|
if (null === input_stored_object) {
|
||||||
@@ -26,9 +29,10 @@ const startApp = (
|
|||||||
const app = createApp({
|
const app = createApp({
|
||||||
template:
|
template:
|
||||||
'<drop-file-widget :existingDoc="this.$data.existingDoc" :allowRemove="true" @addDocument="this.addDocument" @removeDocument="removeDocument"></drop-file-widget>',
|
'<drop-file-widget :existingDoc="this.$data.existingDoc" :allowRemove="true" @addDocument="this.addDocument" @removeDocument="removeDocument"></drop-file-widget>',
|
||||||
data(vm) {
|
data() {
|
||||||
return {
|
return {
|
||||||
existingDoc: existingDoc,
|
existingDoc: existingDoc,
|
||||||
|
inputTitle: inputTitle,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
@@ -38,10 +42,13 @@ const startApp = (
|
|||||||
addDocument: function ({
|
addDocument: function ({
|
||||||
stored_object,
|
stored_object,
|
||||||
stored_object_version,
|
stored_object_version,
|
||||||
|
file_name,
|
||||||
}: {
|
}: {
|
||||||
stored_object: StoredObject;
|
stored_object: StoredObject;
|
||||||
stored_object_version: StoredObjectVersion;
|
stored_object_version: StoredObjectVersion;
|
||||||
|
file_name: string;
|
||||||
}): void {
|
}): void {
|
||||||
|
stored_object.title = file_name;
|
||||||
console.log("object added", stored_object);
|
console.log("object added", stored_object);
|
||||||
console.log("version added", stored_object_version);
|
console.log("version added", stored_object_version);
|
||||||
this.$data.existingDoc = stored_object;
|
this.$data.existingDoc = stored_object;
|
||||||
@@ -49,6 +56,11 @@ const startApp = (
|
|||||||
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?.value) {
|
||||||
|
this.$data.inputTitle.value = file_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
removeDocument: function (object: StoredObject): void {
|
removeDocument: function (object: StoredObject): void {
|
||||||
console.log("catch remove document", object);
|
console.log("catch remove document", object);
|
||||||
|
@@ -2,26 +2,28 @@
|
|||||||
<teleport to="body">
|
<teleport to="body">
|
||||||
<modal v-if="modalOpen" @close="modalOpen = false">
|
<modal v-if="modalOpen" @close="modalOpen = false">
|
||||||
<template v-slot:header>
|
<template v-slot:header>
|
||||||
<h2>{{ $t("signature_confirmation") }}</h2>
|
<h2>{{ trans(SIGNATURES_SIGNATURE_CONFIRMATION) }}</h2>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:body>
|
<template v-slot:body>
|
||||||
<div class="signature-modal-body text-center" v-if="loading">
|
<div class="signature-modal-body text-center" v-if="loading">
|
||||||
<p>{{ $t("electronic_signature_in_progress") }}</p>
|
<p>
|
||||||
|
{{ trans(SIGNATURES_ELECTRONIC_SIGNATURE_IN_PROGRESS) }}
|
||||||
|
</p>
|
||||||
<div class="loading">
|
<div class="loading">
|
||||||
<i
|
<i
|
||||||
class="fa fa-circle-o-notch fa-spin fa-3x"
|
class="fa fa-circle-o-notch fa-spin fa-3x"
|
||||||
:title="$t('loading')"
|
:title="trans(SIGNATURES_LOADING)"
|
||||||
></i>
|
></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="signature-modal-body text-center" v-else>
|
<div class="signature-modal-body text-center" v-else>
|
||||||
<p>{{ $t("you_are_going_to_sign") }}</p>
|
<p>{{ trans(SIGNATURES_YOU_ARE_GOING_TO_SIGN) }}</p>
|
||||||
<p>{{ $t("are_you_sure") }}</p>
|
<p>{{ trans(SIGNATURES_ARE_YOU_SURE) }}</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:footer>
|
<template v-slot:footer>
|
||||||
<button class="btn btn-action" @click.prevent="confirmSign">
|
<button class="btn btn-action" @click.prevent="confirmSign">
|
||||||
{{ $t("yes") }}
|
{{ trans(SIGNATURES_YES) }}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
</modal>
|
</modal>
|
||||||
@@ -82,28 +84,39 @@
|
|||||||
@change="toggleMultiPage"
|
@change="toggleMultiPage"
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label" for="checkboxMulti">
|
<label class="form-check-label" for="checkboxMulti">
|
||||||
{{ $t("all_pages") }}
|
{{ trans(SIGNATURES_ALL_PAGES) }}
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="signature.zones.length > 0"
|
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
|
||||||
:disabled="isFirstSignatureZone"
|
class="btn btn-light btn-sm"
|
||||||
|
@click="goToSignatureZoneUnique"
|
||||||
|
>
|
||||||
|
{{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="signature.zones.length > 1"
|
||||||
|
class="col-5 p-0 text-center turnSignature"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
:disabled="isFirstSignatureZone()"
|
||||||
class="btn btn-light btn-sm"
|
class="btn btn-light btn-sm"
|
||||||
@click="turnSignature(-1)"
|
@click="turnSignature(-1)"
|
||||||
>
|
>
|
||||||
{{ $t("last_zone") }}
|
{{ trans(SIGNATURES_LAST_ZONE) }}
|
||||||
</button>
|
</button>
|
||||||
<span>|</span>
|
<span>|</span>
|
||||||
<button
|
<button
|
||||||
:disabled="isLastSignatureZone"
|
:disabled="isLastSignatureZone()"
|
||||||
class="btn btn-light btn-sm"
|
class="btn btn-light btn-sm"
|
||||||
@click="turnSignature(1)"
|
@click="turnSignature(1)"
|
||||||
>
|
>
|
||||||
{{ $t("next_zone") }}
|
{{ trans(SIGNATURES_NEXT_ZONE) }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col text-end" v-if="signedState !== 'signed'">
|
<div class="col text-end" v-if="signedState !== 'signed'">
|
||||||
@@ -112,9 +125,9 @@
|
|||||||
:hidden="!userSignatureZone"
|
:hidden="!userSignatureZone"
|
||||||
@click="undoSign"
|
@click="undoSign"
|
||||||
v-if="signature.zones.length > 1"
|
v-if="signature.zones.length > 1"
|
||||||
:title="$t('choose_another_signature')"
|
:title="trans(SIGNATURES_CHOOSE_ANOTHER_SIGNATURE)"
|
||||||
>
|
>
|
||||||
{{ $t("another_zone") }}
|
{{ trans(SIGNATURES_ANOTHER_ZONE) }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-misc btn-sm"
|
class="btn btn-misc btn-sm"
|
||||||
@@ -122,7 +135,7 @@
|
|||||||
@click="undoSign"
|
@click="undoSign"
|
||||||
v-else
|
v-else
|
||||||
>
|
>
|
||||||
{{ $t("cancel") }}
|
{{ trans(SIGNATURES_CANCEL) }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="userSignatureZone === null"
|
v-if="userSignatureZone === null"
|
||||||
@@ -134,7 +147,7 @@
|
|||||||
active: canvasEvent === 'add',
|
active: canvasEvent === 'add',
|
||||||
}"
|
}"
|
||||||
@click="toggleAddZone()"
|
@click="toggleAddZone()"
|
||||||
:title="$t('add_sign_zone')"
|
:title="trans(SIGNATURES_ADD_SIGN_ZONE)"
|
||||||
>
|
>
|
||||||
<template v-if="canvasEvent === 'add'">
|
<template v-if="canvasEvent === 'add'">
|
||||||
<div
|
<div
|
||||||
@@ -186,48 +199,70 @@
|
|||||||
@change="toggleMultiPage"
|
@change="toggleMultiPage"
|
||||||
/>
|
/>
|
||||||
<label class="form-check-label" for="checkboxMulti">
|
<label class="form-check-label" for="checkboxMulti">
|
||||||
{{ $t("see_all_pages") }}
|
{{ trans(SIGNATURES_SEE_ALL_PAGES) }}
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="signature.zones.length > 0 && 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
|
||||||
:disabled="!hasSignatureZoneSelected"
|
|
||||||
class="btn btn-light btn-sm"
|
class="btn btn-light btn-sm"
|
||||||
@click="turnSignature(-1)"
|
@click="goToSignatureZoneUnique"
|
||||||
>
|
>
|
||||||
{{ $t("last_zone") }}
|
{{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
|
||||||
</button>
|
|
||||||
<span>|</span>
|
|
||||||
<button
|
|
||||||
:disabled="isLastSignatureZone"
|
|
||||||
class="btn btn-light btn-sm"
|
|
||||||
@click="turnSignature(1)"
|
|
||||||
>
|
|
||||||
{{ $t("next_zone") }}
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="signature.zones.length > 0 && 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-xl-none text-center turnSignature p-0"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
:disabled="isFirstSignatureZone"
|
:disabled="isFirstSignatureZone()"
|
||||||
class="btn btn-light btn-sm"
|
class="btn btn-light btn-sm"
|
||||||
@click="turnSignature(-1)"
|
@click="turnSignature(-1)"
|
||||||
>
|
>
|
||||||
{{ $t("last_sign_zone") }}
|
{{ trans(SIGNATURES_LAST_ZONE) }}
|
||||||
</button>
|
</button>
|
||||||
<span>|</span>
|
<span>|</span>
|
||||||
<button
|
<button
|
||||||
:disabled="isLastSignatureZone"
|
:disabled="isLastSignatureZone()"
|
||||||
class="btn btn-light btn-sm"
|
class="btn btn-light btn-sm"
|
||||||
@click="turnSignature(1)"
|
@click="turnSignature(1)"
|
||||||
>
|
>
|
||||||
{{ $t("next_sign_zone") }}
|
{{ trans(SIGNATURES_NEXT_ZONE) }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="signature.zones.length === 1 && signedState !== 'signed'"
|
||||||
|
class="col-4 d-none d-xl-flex p-0 text-center turnSignature"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="btn btn-light btn-sm"
|
||||||
|
@click="goToSignatureZoneUnique"
|
||||||
|
>
|
||||||
|
{{ trans(SIGNATURES_GO_TO_SIGNATURE_UNIQUE) }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="signature.zones.length > 1 && signedState !== 'signed'"
|
||||||
|
class="col-4 d-none d-xl-flex p-0 text-center turnSignature"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
:disabled="isFirstSignatureZone()"
|
||||||
|
class="btn btn-light btn-sm"
|
||||||
|
@click="turnSignature(-1)"
|
||||||
|
>
|
||||||
|
{{ trans(SIGNATURES_LAST_SIGN_ZONE) }}
|
||||||
|
</button>
|
||||||
|
<span>|</span>
|
||||||
|
<button
|
||||||
|
:disabled="isLastSignatureZone()"
|
||||||
|
class="btn btn-light btn-sm"
|
||||||
|
@click="turnSignature(1)"
|
||||||
|
>
|
||||||
|
{{ trans(SIGNATURES_NEXT_SIGN_ZONE) }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col text-end" v-if="signedState !== 'signed'">
|
<div class="col text-end" v-if="signedState !== 'signed'">
|
||||||
@@ -237,7 +272,7 @@
|
|||||||
@click="undoSign"
|
@click="undoSign"
|
||||||
v-if="signature.zones.length > 1"
|
v-if="signature.zones.length > 1"
|
||||||
>
|
>
|
||||||
{{ $t("choose_another_signature") }}
|
{{ trans(SIGNATURES_CHOOSE_ANOTHER_SIGNATURE) }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-misc btn-sm"
|
class="btn btn-misc btn-sm"
|
||||||
@@ -245,7 +280,7 @@
|
|||||||
@click="undoSign"
|
@click="undoSign"
|
||||||
v-else
|
v-else
|
||||||
>
|
>
|
||||||
{{ $t("cancel") }}
|
{{ trans(SIGNATURES_CANCEL) }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="userSignatureZone === null"
|
v-if="userSignatureZone === null"
|
||||||
@@ -257,13 +292,13 @@
|
|||||||
active: canvasEvent === 'add',
|
active: canvasEvent === 'add',
|
||||||
}"
|
}"
|
||||||
@click="toggleAddZone()"
|
@click="toggleAddZone()"
|
||||||
:title="$t('add_sign_zone')"
|
:title="trans(SIGNATURES_ADD_SIGN_ZONE)"
|
||||||
>
|
>
|
||||||
<template v-if="canvasEvent !== 'add'">
|
<template v-if="canvasEvent !== 'add'">
|
||||||
{{ $t("add_zone") }}
|
{{ trans(SIGNATURES_ADD_ZONE) }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ $t("click_on_document") }}
|
{{ trans(SIGNATURES_CLICK_ON_DOCUMENT) }}
|
||||||
<div
|
<div
|
||||||
class="spinner-border spinner-border-sm"
|
class="spinner-border spinner-border-sm"
|
||||||
role="status"
|
role="status"
|
||||||
@@ -297,10 +332,10 @@
|
|||||||
v-if="signedState !== 'signed'"
|
v-if="signedState !== 'signed'"
|
||||||
:href="getReturnPath()"
|
:href="getReturnPath()"
|
||||||
>
|
>
|
||||||
{{ $t("cancel") }}
|
{{ trans(SIGNATURES_CANCEL) }}
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-misc" v-else :href="getReturnPath()">
|
<a class="btn btn-misc" v-else :href="getReturnPath()">
|
||||||
{{ $t("return") }}
|
{{ trans(SIGNATURES_RETURN) }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col text-end" v-if="signedState !== 'signed'">
|
<div class="col text-end" v-if="signedState !== 'signed'">
|
||||||
@@ -309,7 +344,7 @@
|
|||||||
:disabled="!userSignatureZone"
|
:disabled="!userSignatureZone"
|
||||||
@click="sign"
|
@click="sign"
|
||||||
>
|
>
|
||||||
{{ $t("sign") }}
|
{{ trans(SIGNATURES_SIGN) }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4" v-else></div>
|
<div class="col-4" v-else></div>
|
||||||
@@ -318,7 +353,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, Ref, computed } from "vue";
|
import { ref, Ref } from "vue";
|
||||||
import { useToast } from "vue-toast-notification";
|
import { useToast } from "vue-toast-notification";
|
||||||
import "vue-toast-notification/dist/theme-sugar.css";
|
import "vue-toast-notification/dist/theme-sugar.css";
|
||||||
import {
|
import {
|
||||||
@@ -329,13 +364,38 @@ import {
|
|||||||
SignedState,
|
SignedState,
|
||||||
ZoomLevel,
|
ZoomLevel,
|
||||||
} from "../../types";
|
} from "../../types";
|
||||||
import { makeFetch } from "../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
|
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
||||||
import * as pdfjsLib from "pdfjs-dist";
|
import * as pdfjsLib from "pdfjs-dist";
|
||||||
import {
|
import {
|
||||||
PDFDocumentProxy,
|
PDFDocumentProxy,
|
||||||
PDFPageProxy,
|
PDFPageProxy,
|
||||||
} from "pdfjs-dist/types/src/display/api";
|
} from "pdfjs-dist/types/src/display/api";
|
||||||
|
|
||||||
|
import {
|
||||||
|
SIGNATURES_YES,
|
||||||
|
SIGNATURES_ARE_YOU_SURE,
|
||||||
|
SIGNATURES_YOU_ARE_GOING_TO_SIGN,
|
||||||
|
SIGNATURES_SIGNATURE_CONFIRMATION,
|
||||||
|
SIGNATURES_SIGN,
|
||||||
|
SIGNATURES_CHOOSE_ANOTHER_SIGNATURE,
|
||||||
|
SIGNATURES_CANCEL,
|
||||||
|
SIGNATURES_LAST_SIGN_ZONE,
|
||||||
|
SIGNATURES_NEXT_SIGN_ZONE,
|
||||||
|
SIGNATURES_ADD_SIGN_ZONE,
|
||||||
|
SIGNATURES_CLICK_ON_DOCUMENT,
|
||||||
|
SIGNATURES_LAST_ZONE,
|
||||||
|
SIGNATURES_NEXT_ZONE,
|
||||||
|
SIGNATURES_ADD_ZONE,
|
||||||
|
SIGNATURES_ANOTHER_ZONE,
|
||||||
|
SIGNATURES_ELECTRONIC_SIGNATURE_IN_PROGRESS,
|
||||||
|
SIGNATURES_LOADING,
|
||||||
|
SIGNATURES_RETURN,
|
||||||
|
SIGNATURES_SEE_ALL_PAGES,
|
||||||
|
SIGNATURES_ALL_PAGES,
|
||||||
|
SIGNATURES_GO_TO_SIGNATURE_UNIQUE,
|
||||||
|
trans,
|
||||||
|
} from "translator";
|
||||||
|
|
||||||
// @ts-ignore incredible but the console.log is needed
|
// @ts-ignore incredible but the console.log is needed
|
||||||
import * as PdfWorker from "pdfjs-dist/build/pdf.worker.mjs";
|
import * as PdfWorker from "pdfjs-dist/build/pdf.worker.mjs";
|
||||||
console.log(PdfWorker);
|
console.log(PdfWorker);
|
||||||
@@ -416,19 +476,15 @@ const $toast = useToast();
|
|||||||
const signature = window.signature;
|
const signature = window.signature;
|
||||||
|
|
||||||
const isFirstSignatureZone = () =>
|
const isFirstSignatureZone = () =>
|
||||||
userSignatureZone.value?.index ? userSignatureZone.value.index < 1 : false;
|
userSignatureZone.value?.index != null
|
||||||
|
? userSignatureZone.value.index < 1
|
||||||
|
: false;
|
||||||
|
|
||||||
const isLastSignatureZone = () =>
|
const isLastSignatureZone = () =>
|
||||||
userSignatureZone.value?.index
|
userSignatureZone.value?.index
|
||||||
? userSignatureZone.value.index >= signature.zones.length - 1
|
? userSignatureZone.value.index >= signature.zones.length - 1
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the user has selected a user zone (existing on the doc or created by the user)
|
|
||||||
*/
|
|
||||||
const hasSignatureZoneSelected = computed<boolean>(
|
|
||||||
() => userSignatureZone.value !== null,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setZoomLevel = async (zoomLevel: string) => {
|
const setZoomLevel = async (zoomLevel: string) => {
|
||||||
zoom.value = Number.parseFloat(zoomLevel);
|
zoom.value = Number.parseFloat(zoomLevel);
|
||||||
await resetPages();
|
await resetPages();
|
||||||
@@ -600,6 +656,15 @@ const turnPage = async (upOrDown: number) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const selectZoneInCanvas = (signatureZone: SignatureZone) => {
|
||||||
|
page.value = signatureZone.PDFPage.index + 1;
|
||||||
|
const canvas = getCanvas(signatureZone.PDFPage.index + 1);
|
||||||
|
selectZone(signatureZone, canvas);
|
||||||
|
canvas.scrollIntoView();
|
||||||
|
};
|
||||||
|
|
||||||
|
const goToSignatureZoneUnique = () => selectZoneInCanvas(signature.zones[0]);
|
||||||
|
|
||||||
const turnSignature = async (upOrDown: number) => {
|
const turnSignature = async (upOrDown: number) => {
|
||||||
let zoneIndex = userSignatureZone.value?.index ?? -1;
|
let zoneIndex = userSignatureZone.value?.index ?? -1;
|
||||||
if (zoneIndex < -1) {
|
if (zoneIndex < -1) {
|
||||||
@@ -612,10 +677,7 @@ const turnSignature = async (upOrDown: number) => {
|
|||||||
}
|
}
|
||||||
let currentZone = signature.zones[zoneIndex];
|
let currentZone = signature.zones[zoneIndex];
|
||||||
if (currentZone) {
|
if (currentZone) {
|
||||||
page.value = currentZone.PDFPage.index + 1;
|
selectZoneInCanvas(currentZone);
|
||||||
const canvas = getCanvas(currentZone.PDFPage.index + 1);
|
|
||||||
selectZone(currentZone, canvas);
|
|
||||||
canvas.scrollIntoView();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -23,6 +23,7 @@ const emit =
|
|||||||
{
|
{
|
||||||
stored_object_version: StoredObjectVersionCreated,
|
stored_object_version: StoredObjectVersionCreated,
|
||||||
stored_object: StoredObject,
|
stored_object: StoredObject,
|
||||||
|
file_name: string,
|
||||||
},
|
},
|
||||||
) => void
|
) => void
|
||||||
>();
|
>();
|
||||||
@@ -114,7 +115,21 @@ const handleFile = async (file: File): Promise<void> => {
|
|||||||
persisted: false,
|
persisted: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
emit("addDocument", { stored_object, stored_object_version });
|
const fileName = file.name;
|
||||||
|
let file_name = "Nouveau document";
|
||||||
|
const file_name_split = fileName.split(".");
|
||||||
|
if (file_name_split.length > 1) {
|
||||||
|
const extension = file_name_split
|
||||||
|
? file_name_split[file_name_split.length - 1]
|
||||||
|
: "";
|
||||||
|
file_name = fileName.replace(extension, "").slice(0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit("addDocument", {
|
||||||
|
stored_object,
|
||||||
|
stored_object_version,
|
||||||
|
file_name: file_name,
|
||||||
|
});
|
||||||
uploading.value = false;
|
uploading.value = false;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@@ -20,6 +20,7 @@ const emit = defineEmits<{
|
|||||||
{
|
{
|
||||||
stored_object: StoredObject,
|
stored_object: StoredObject,
|
||||||
stored_object_version: StoredObjectVersion,
|
stored_object_version: StoredObjectVersion,
|
||||||
|
file_name: string,
|
||||||
},
|
},
|
||||||
): void;
|
): void;
|
||||||
(e: "removeDocument"): void;
|
(e: "removeDocument"): void;
|
||||||
@@ -42,14 +43,16 @@ const buttonState = computed<"add" | "replace">(() => {
|
|||||||
function onAddDocument({
|
function onAddDocument({
|
||||||
stored_object,
|
stored_object,
|
||||||
stored_object_version,
|
stored_object_version,
|
||||||
|
file_name,
|
||||||
}: {
|
}: {
|
||||||
stored_object: StoredObject;
|
stored_object: StoredObject;
|
||||||
stored_object_version: StoredObjectVersion;
|
stored_object_version: StoredObjectVersion;
|
||||||
|
file_name: string;
|
||||||
}): void {
|
}): void {
|
||||||
const message =
|
const message =
|
||||||
buttonState.value === "add" ? "Document ajouté" : "Document remplacé";
|
buttonState.value === "add" ? "Document ajouté" : "Document remplacé";
|
||||||
$toast.success(message);
|
$toast.success(message);
|
||||||
emit("addDocument", { stored_object_version, stored_object });
|
emit("addDocument", { stored_object_version, stored_object, file_name });
|
||||||
state.showModal = false;
|
state.showModal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@ const emit = defineEmits<{
|
|||||||
{
|
{
|
||||||
stored_object: StoredObject,
|
stored_object: StoredObject,
|
||||||
stored_object_version: StoredObjectVersion,
|
stored_object_version: StoredObjectVersion,
|
||||||
|
file_name: string,
|
||||||
},
|
},
|
||||||
): void;
|
): void;
|
||||||
(e: "removeDocument"): void;
|
(e: "removeDocument"): void;
|
||||||
@@ -53,11 +54,13 @@ const dav_link_href = computed<string | undefined>(() => {
|
|||||||
const onAddDocument = ({
|
const onAddDocument = ({
|
||||||
stored_object,
|
stored_object,
|
||||||
stored_object_version,
|
stored_object_version,
|
||||||
|
file_name,
|
||||||
}: {
|
}: {
|
||||||
stored_object: StoredObject;
|
stored_object: StoredObject;
|
||||||
stored_object_version: StoredObjectVersion;
|
stored_object_version: StoredObjectVersion;
|
||||||
|
file_name: string;
|
||||||
}): void => {
|
}): void => {
|
||||||
emit("addDocument", { stored_object, stored_object_version });
|
emit("addDocument", { stored_object, stored_object_version, file_name });
|
||||||
};
|
};
|
||||||
|
|
||||||
const onRemoveDocument = (e: Event): void => {
|
const onRemoveDocument = (e: Event): void => {
|
||||||
|
@@ -53,7 +53,7 @@ const onRestored = ({
|
|||||||
<template>
|
<template>
|
||||||
<template v-if="props.versions.length > 0">
|
<template v-if="props.versions.length > 0">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<template v-for="v in props.versions">
|
<template v-for="v in props.versions" :key="v.id">
|
||||||
<history-button-list-item
|
<history-button-list-item
|
||||||
:version="v"
|
:version="v"
|
||||||
:can-edit="canEdit"
|
:can-edit="canEdit"
|
||||||
|
@@ -32,13 +32,17 @@ const onRestore = ({
|
|||||||
emit("restoreVersion", { newVersion });
|
emit("restoreVersion", { newVersion });
|
||||||
};
|
};
|
||||||
|
|
||||||
const isKeptBeforeConversion = computed<boolean>(() =>
|
const isKeptBeforeConversion = computed<boolean>(() => {
|
||||||
props.version["point-in-times"].reduce(
|
if ("point-in-times" in props.version) {
|
||||||
(accumulator: boolean, pit: StoredObjectPointInTime) =>
|
return props.version["point-in-times"].reduce(
|
||||||
accumulator || "keep-before-conversion" === pit.reason,
|
(accumulator: boolean, pit: StoredObjectPointInTime) =>
|
||||||
false,
|
accumulator || "keep-before-conversion" === pit.reason,
|
||||||
),
|
false,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const isRestored = computed<boolean>(
|
const isRestored = computed<boolean>(
|
||||||
() => props.version.version > 0 && null !== props.version["from-restored"],
|
() => props.version.version > 0 && null !== props.version["from-restored"],
|
||||||
@@ -90,11 +94,11 @@ const classes = computed<{
|
|||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<file-icon :type="version.type"></file-icon>
|
<file-icon :type="version.type"></file-icon>
|
||||||
<span
|
<span
|
||||||
><strong>#{{ version.version + 1 }}</strong></span
|
><strong> #{{ version.version + 1 }} </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
|
||||||
|
@@ -23,7 +23,7 @@ License * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
{{ encore_entry_link_tags("mod_document_action_buttons_group") }}
|
{{ encore_entry_link_tags("mod_document_action_buttons_group") }}
|
||||||
{% endblock %} {% block content %}
|
{% endblock %} {% block content %}
|
||||||
|
|
||||||
<div class="col-md-10 col-xxl">
|
<div class="document-list">
|
||||||
<h1>
|
<h1>
|
||||||
{{ 'Documents for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}
|
{{ 'Documents for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}
|
||||||
</h1>
|
</h1>
|
||||||
|
@@ -3,54 +3,56 @@
|
|||||||
{% import '@ChillPerson/Macro/updatedBy.html.twig' as mmm %}
|
{% import '@ChillPerson/Macro/updatedBy.html.twig' as mmm %}
|
||||||
|
|
||||||
<div class="item-row">
|
<div class="item-row">
|
||||||
<div class="item-col" style="width: unset">
|
<!-- person document or accompanying course document -->
|
||||||
{% if document.object.isPending %}
|
<div class="item-two-col-grid">
|
||||||
<div class="badge text-bg-info" data-docgen-is-pending="{{ document.object.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
|
<div class="title">
|
||||||
{% elseif document.object.isFailure %}
|
{% if document.object.isPending %}
|
||||||
<div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
|
<div class="badge text-bg-info" data-docgen-is-pending="{{ document.object.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
|
||||||
{% endif %}
|
{% elseif document.object.isFailure %}
|
||||||
|
<div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if context == 'person' and accompanyingCourse is defined %}
|
<div class="denomination h2">
|
||||||
<div>
|
{{ document.title|chill_print_or_message("No title") }}
|
||||||
<span class="badge bg-primary">
|
|
||||||
<i class="fa fa-random"></i> {{ accompanyingCourse.id }}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
{% elseif context == 'accompanying-period' and person is defined %}
|
{% if document.object.type is not empty %}
|
||||||
<div>
|
<div>
|
||||||
<span class="badge bg-primary">
|
{{ mm.mimeIcon(document.object.type) }}
|
||||||
{{ 'Document from person %name%'|trans({ '%name%': document.person|chill_entity_render_string }) }}
|
</div>
|
||||||
</span>
|
{% endif %}
|
||||||
</div>
|
{% if document.category %}
|
||||||
|
<div>
|
||||||
{% endif %}
|
<p>{{ document.category.name|localize_translatable_string }}</p>
|
||||||
<div class="denomination h2">
|
</div>
|
||||||
{{ document.title|chill_print_or_message("No title") }}
|
{% endif %}
|
||||||
</div>
|
{% if document.object.hasTemplate %}
|
||||||
{% if document.object.type is not empty %}
|
<div>
|
||||||
<div>
|
<p>{{ document.object.template.name|localize_translatable_string }}</p>
|
||||||
{{ mm.mimeIcon(document.object.type) }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div>
|
|
||||||
<p>{{ document.category.name|localize_translatable_string }}</p>
|
|
||||||
</div>
|
|
||||||
{% if document.object.hasTemplate %}
|
|
||||||
<div>
|
|
||||||
<p>{{ document.object.template.name|localize_translatable_string }}</p>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="item-col">
|
|
||||||
<div class="container">
|
|
||||||
{% if document.date is not null %}
|
|
||||||
<div class="dates row text-end">
|
|
||||||
<span>{{ document.date|format_date('short') }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% if document.date is not null %}
|
||||||
|
<div class="aside">
|
||||||
|
<div class="dates row text-end">
|
||||||
|
<span>{{ document.date|format_date('short') }}</span>
|
||||||
|
</div>
|
||||||
|
{% if context == 'person' and accompanyingCourse is defined %}
|
||||||
|
<div class="text-end">
|
||||||
|
<span class="badge bg-primary">
|
||||||
|
<i class="fa fa-random"></i> {{ accompanyingCourse.id }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% elseif context == 'accompanying-period' and person is defined %}
|
||||||
|
<div class="text-end">
|
||||||
|
<span class="badge bg-primary">
|
||||||
|
{{ document.person|chill_entity_render_string }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% if document.description is not empty %}
|
{% if document.description is not empty %}
|
||||||
<div class="item-row">
|
<div class="item-row">
|
||||||
|
@@ -62,7 +62,15 @@ final readonly class RemoveOldVersionMessageHandler implements MessageHandlerInt
|
|||||||
|
|
||||||
$storedObject = $storedObjectVersion->getStoredObject();
|
$storedObject = $storedObjectVersion->getStoredObject();
|
||||||
|
|
||||||
$this->storedObjectManager->delete($storedObjectVersion);
|
if ($this->storedObjectManager->exists($storedObjectVersion)) {
|
||||||
|
$this->storedObjectManager->delete($storedObjectVersion);
|
||||||
|
} else {
|
||||||
|
$this->logger->notice(
|
||||||
|
self::LOG_PREFIX.'Stored object version does not exists any more.',
|
||||||
|
['storedObjectVersionName' => $storedObjectVersion->getFilename()],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// to ensure an immediate deletion
|
// to ensure an immediate deletion
|
||||||
$this->entityManager->remove($storedObjectVersion);
|
$this->entityManager->remove($storedObjectVersion);
|
||||||
|
|
||||||
|
@@ -44,6 +44,7 @@ class RemoveOldVersionMessageHandlerTest extends TestCase
|
|||||||
$entityManager->expects($this->once())->method('clear');
|
$entityManager->expects($this->once())->method('clear');
|
||||||
|
|
||||||
$storedObjectManager = $this->createMock(StoredObjectManagerInterface::class);
|
$storedObjectManager = $this->createMock(StoredObjectManagerInterface::class);
|
||||||
|
$storedObjectManager->expects($this->once())->method('exists')->willReturn(true);
|
||||||
$storedObjectManager->expects($this->once())->method('delete')->with($this->identicalTo($version));
|
$storedObjectManager->expects($this->once())->method('delete')->with($this->identicalTo($version));
|
||||||
|
|
||||||
$handler = new RemoveOldVersionMessageHandler($storedObjectVersionRepository, new NullLogger(), $entityManager, $storedObjectManager, new MockClock());
|
$handler = new RemoveOldVersionMessageHandler($storedObjectVersionRepository, new NullLogger(), $entityManager, $storedObjectManager, new MockClock());
|
||||||
@@ -51,6 +52,29 @@ class RemoveOldVersionMessageHandlerTest extends TestCase
|
|||||||
$handler(new RemoveOldVersionMessage(1));
|
$handler(new RemoveOldVersionMessage(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testInvokeForVersionNotExisting(): void
|
||||||
|
{
|
||||||
|
$object = new StoredObject();
|
||||||
|
$version = $object->registerVersion();
|
||||||
|
$storedObjectVersionRepository = $this->createMock(StoredObjectVersionRepository::class);
|
||||||
|
$storedObjectVersionRepository->expects($this->once())->method('find')
|
||||||
|
->with($this->identicalTo(1))
|
||||||
|
->willReturn($version);
|
||||||
|
|
||||||
|
$entityManager = $this->createMock(EntityManagerInterface::class);
|
||||||
|
$entityManager->expects($this->once())->method('remove')->with($this->identicalTo($version));
|
||||||
|
$entityManager->expects($this->once())->method('flush');
|
||||||
|
$entityManager->expects($this->once())->method('clear');
|
||||||
|
|
||||||
|
$storedObjectManager = $this->createMock(StoredObjectManagerInterface::class);
|
||||||
|
$storedObjectManager->expects($this->once())->method('exists')->willReturn(false);
|
||||||
|
$storedObjectManager->expects($this->never())->method('delete')->with($this->identicalTo($version));
|
||||||
|
|
||||||
|
$handler = new RemoveOldVersionMessageHandler($storedObjectVersionRepository, new NullLogger(), $entityManager, $storedObjectManager, new MockClock());
|
||||||
|
|
||||||
|
$handler(new RemoveOldVersionMessage(1));
|
||||||
|
}
|
||||||
|
|
||||||
public function testInvokeWithStoredObjectToDelete(): void
|
public function testInvokeWithStoredObjectToDelete(): void
|
||||||
{
|
{
|
||||||
$object = new StoredObject();
|
$object = new StoredObject();
|
||||||
@@ -123,6 +147,6 @@ class DummyStoredObjectManager implements StoredObjectManagerInterface
|
|||||||
|
|
||||||
public function exists(StoredObject|StoredObjectVersion $document): bool
|
public function exists(StoredObject|StoredObjectVersion $document): bool
|
||||||
{
|
{
|
||||||
throw new \RuntimeException();
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -99,3 +99,30 @@ CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE: Modifier un document
|
|||||||
entity_display_title:
|
entity_display_title:
|
||||||
Document (n°%doc%): "Document (n°%doc%)"
|
Document (n°%doc%): "Document (n°%doc%)"
|
||||||
Doc for evaluation (n°%eval%): Document de l'évaluation n°%eval%
|
Doc for evaluation (n°%eval%): Document de l'évaluation n°%eval%
|
||||||
|
|
||||||
|
|
||||||
|
# SIGNATURES
|
||||||
|
|
||||||
|
signatures:
|
||||||
|
yes: Oui
|
||||||
|
are_you_sure: Êtes-vous sûr·e?
|
||||||
|
you_are_going_to_sign: Vous allez signer le document
|
||||||
|
signature_confirmation: Confirmation de la signature
|
||||||
|
sign: Signer
|
||||||
|
choose_another_signature: Choisir une autre zone
|
||||||
|
cancel: Annuler
|
||||||
|
last_sign_zone: Zone de signature précédente
|
||||||
|
next_sign_zone: Zone de signature suivante
|
||||||
|
add_sign_zone: Ajouter une zone de signature
|
||||||
|
click_on_document: Cliquer sur le document
|
||||||
|
last_zone: Zone précédente
|
||||||
|
next_zone: Zone suivante
|
||||||
|
add_zone: Ajouter une zone
|
||||||
|
another_zone: Autre zone
|
||||||
|
electronic_signature_in_progress: Signature électronique en cours...
|
||||||
|
loading: Chargement...
|
||||||
|
remove_sign_zone: Enlever la zone
|
||||||
|
return: Retour
|
||||||
|
see_all_pages: Voir toutes les pages
|
||||||
|
all_pages: Toutes les pages
|
||||||
|
go_to_signature_unique: Aller à la zone de signature
|
||||||
|
@@ -33,6 +33,8 @@
|
|||||||
|
|
||||||
@import './scss/hover.scss';
|
@import './scss/hover.scss';
|
||||||
|
|
||||||
|
@import './scss/comment-editor.scss';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BASE LAYOUT POSITION
|
* BASE LAYOUT POSITION
|
||||||
*/
|
*/
|
||||||
|
@@ -0,0 +1,39 @@
|
|||||||
|
.comment-container {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-button {
|
||||||
|
background-color: white;
|
||||||
|
font-size: .8rem;
|
||||||
|
text-decoration: none;
|
||||||
|
position: absolute;
|
||||||
|
bottom: -10px;
|
||||||
|
left: 20px;
|
||||||
|
padding: 2px 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 10;
|
||||||
|
transition: left 0.1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rich-editor-active .toggle-button {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-wrapper textarea {
|
||||||
|
resize: vertical;
|
||||||
|
min-height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-container {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-wrapper {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-textarea {
|
||||||
|
display: none;
|
||||||
|
}
|
@@ -25,7 +25,34 @@ div.flex-table {
|
|||||||
div.item-col:last-child {
|
div.item-col:last-child {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.item-two-col-grid {
|
||||||
|
display: grid;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: stretch;
|
||||||
|
|
||||||
|
@include media-breakpoint-up(lg) {
|
||||||
|
grid-template-areas:
|
||||||
|
"title aside";
|
||||||
|
grid-template-columns: 1fr minmax(8rem, 1fr);
|
||||||
|
column-gap: 0.5em;
|
||||||
|
}
|
||||||
|
@include media-breakpoint-down(lg) {
|
||||||
|
grid-template-areas:
|
||||||
|
"aside"
|
||||||
|
"title";
|
||||||
|
}
|
||||||
|
|
||||||
|
& > div.title {
|
||||||
|
grid-area: title;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > div.aside {
|
||||||
|
grid-area: aside;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h2, h3, h4, dl, p {
|
h2, h3, h4, dl, p {
|
||||||
|
@@ -8,10 +8,10 @@ import {
|
|||||||
Heading,
|
Heading,
|
||||||
Link,
|
Link,
|
||||||
List,
|
List,
|
||||||
} from "ckeditor5";
|
} from 'ckeditor5';
|
||||||
import coreTranslations from "ckeditor5/translations/fr.js";
|
import coreTranslations from 'ckeditor5/translations/fr.js';
|
||||||
|
|
||||||
import "ckeditor5/ckeditor5.css";
|
import 'ckeditor5/ckeditor5.css';
|
||||||
|
|
||||||
import "./index.scss";
|
import "./index.scss";
|
||||||
|
|
||||||
@@ -41,6 +41,8 @@ export default {
|
|||||||
"redo",
|
"redo",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
translations: [coreTranslations],
|
translations: [
|
||||||
|
coreTranslations
|
||||||
|
],
|
||||||
licenseKey: "GPL",
|
licenseKey: "GPL",
|
||||||
};
|
} ;
|
||||||
|
@@ -1,12 +1,23 @@
|
|||||||
import config from "./editor_config";
|
import App from "../../vuejs/CommentEditor/App.vue"
|
||||||
import { ClassicEditor } from "ckeditor5";
|
import { createApp, reactive } from "vue";
|
||||||
|
|
||||||
const ckeditorFields: NodeListOf<HTMLTextAreaElement> =
|
const ckeditorFields: NodeListOf<HTMLTextAreaElement> =
|
||||||
document.querySelectorAll("textarea[ckeditor]");
|
document.querySelectorAll("[id^='comment-app']");
|
||||||
ckeditorFields.forEach((field: HTMLTextAreaElement): void => {
|
|
||||||
ClassicEditor.create(field, config).catch((error) => {
|
const globalState = reactive({
|
||||||
console.error(error.stack);
|
isSimple: localStorage.getItem('editorMode') === 'simple'
|
||||||
throw error;
|
});
|
||||||
});
|
window.addEventListener('storage', () => {
|
||||||
|
globalState.isSimple = localStorage.getItem('editorMode') === 'simple';
|
||||||
|
});
|
||||||
|
|
||||||
|
ckeditorFields.forEach((field: HTMLTextAreaElement): void => {
|
||||||
|
const app = createApp(App,{
|
||||||
|
fieldName: field.dataset.fieldName,
|
||||||
|
template: `<app></app>`
|
||||||
|
});
|
||||||
|
|
||||||
|
app.provide('globalState', globalState)
|
||||||
|
.component("app", App)
|
||||||
|
.mount(field);
|
||||||
});
|
});
|
||||||
//Fields.push.apply(Fields, document.querySelectorAll('.cf-fields textarea'));
|
|
||||||
|
@@ -10,6 +10,10 @@ let appsPerInput = new Map();
|
|||||||
|
|
||||||
function loadDynamicPicker(element) {
|
function loadDynamicPicker(element) {
|
||||||
let apps = element.querySelectorAll('[data-module="pick-dynamic"]');
|
let apps = element.querySelectorAll('[data-module="pick-dynamic"]');
|
||||||
|
let suggested;
|
||||||
|
let as_id;
|
||||||
|
let submit_on_adding_new_entity;
|
||||||
|
let label;
|
||||||
|
|
||||||
apps.forEach(function (el) {
|
apps.forEach(function (el) {
|
||||||
const isMultiple = parseInt(el.dataset.multiple) === 1,
|
const isMultiple = parseInt(el.dataset.multiple) === 1,
|
||||||
|
@@ -1,45 +0,0 @@
|
|||||||
import { createApp } from "vue";
|
|
||||||
import OpenWopiLink from "ChillMainAssets/vuejs/_components/OpenWopiLink";
|
|
||||||
import { _createI18n } from "ChillMainAssets/vuejs/_js/i18n";
|
|
||||||
|
|
||||||
const i18n = _createI18n({});
|
|
||||||
|
|
||||||
//TODO move to chillDocStore or ChillWopi
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
tags to load module:
|
|
||||||
|
|
||||||
<span data-module="wopi-link"
|
|
||||||
data-wopi-url="{{ path('chill_wopi_file_edit', {'fileId': document.uuid}) }}"
|
|
||||||
data-doc-type="{{ document.type|e('html_attr') }}"
|
|
||||||
data-options="{{ options|json_encode }}"
|
|
||||||
></span>
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
window.addEventListener("DOMContentLoaded", function (e) {
|
|
||||||
document
|
|
||||||
.querySelectorAll('span[data-module="wopi-link"]')
|
|
||||||
.forEach(function (el) {
|
|
||||||
createApp({
|
|
||||||
template:
|
|
||||||
'<open-wopi-link :wopiUrl="wopiUrl" :type="type" :options="options"></open-wopi-link>',
|
|
||||||
components: {
|
|
||||||
OpenWopiLink,
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
wopiUrl: el.dataset.wopiUrl,
|
|
||||||
type: el.dataset.docType,
|
|
||||||
options:
|
|
||||||
el.dataset.options !== "null"
|
|
||||||
? JSON.parse(el.dataset.options)
|
|
||||||
: {},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.use(i18n)
|
|
||||||
.mount(el);
|
|
||||||
});
|
|
||||||
});
|
|
@@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<comment-editor
|
||||||
|
:isSimple="globalState.isSimple"
|
||||||
|
:fieldName="fieldName"
|
||||||
|
@toggle="toggleEditorMode"
|
||||||
|
></comment-editor>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineComponent, inject } from 'vue';
|
||||||
|
import CommentEditor from "../CommentEditor/component/CommentEditor.vue";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "App",
|
||||||
|
components: { CommentEditor },
|
||||||
|
props: {
|
||||||
|
fieldName: String
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const globalState = inject('globalState');
|
||||||
|
const toggleEditorMode = () => {
|
||||||
|
globalState.isSimple = !globalState.isSimple;
|
||||||
|
localStorage.setItem('editorMode', globalState.isSimple ? 'simple' : 'rich');
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
globalState,
|
||||||
|
toggleEditorMode,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
@@ -0,0 +1,58 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="{'editor-container': true, 'rich-editor-active': !isSimple}">
|
||||||
|
<div v-if="!isSimple" class="editor-wrapper">
|
||||||
|
<ckeditor
|
||||||
|
:name="fieldName"
|
||||||
|
:editor="classicEditor"
|
||||||
|
:config="editorConfig"
|
||||||
|
v-model.lazy="content"
|
||||||
|
tag-name="textarea"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else class="editor-wrapper">
|
||||||
|
<textarea
|
||||||
|
v-model.lazy="content"
|
||||||
|
:name="fieldName"
|
||||||
|
class="form-control"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<a @click="toggleSimpleEditor" class="toggle-button">{{ isSimple ? "rich" : "simple" }}</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref, computed, toRefs } from 'vue';
|
||||||
|
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
|
||||||
|
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
|
||||||
|
import { ClassicEditor } from "ckeditor5";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "CommentEditor",
|
||||||
|
components: {
|
||||||
|
ckeditor: Ckeditor,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
type: String,
|
||||||
|
isSimple: Boolean,
|
||||||
|
fieldName: String,
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const { isSimple } = toRefs(props);
|
||||||
|
const content = ref("");
|
||||||
|
const classicEditor = ClassicEditor;
|
||||||
|
const editorConfig = classicEditorConfig;
|
||||||
|
|
||||||
|
const toggleSimpleEditor = () => {
|
||||||
|
emit("toggle");
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
isSimple,
|
||||||
|
content,
|
||||||
|
classicEditor,
|
||||||
|
editorConfig,
|
||||||
|
toggleSimpleEditor,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
@@ -0,0 +1,14 @@
|
|||||||
|
import {personMessages} from "ChillPersonAssets/vuejs/_js/i18n";
|
||||||
|
import {calendarUserSelectorMessages} from "ChillCalendarAssets/vuejs/_components/CalendarUserSelector/js/i18n";
|
||||||
|
import {activityMessages} from "ChillActivityAssets/vuejs/Activity/i18n";
|
||||||
|
|
||||||
|
const appMessages = {
|
||||||
|
fr: {
|
||||||
|
mode: {
|
||||||
|
simple: "Editeur simple",
|
||||||
|
rich: "Editeur riche"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export { appMessages };
|
@@ -26,9 +26,9 @@
|
|||||||
trans(THIRDPARTY_CONTACT_OF)
|
trans(THIRDPARTY_CONTACT_OF)
|
||||||
}}</span>
|
}}</span>
|
||||||
<span v-else-if="props.entity.kind === 'company'">{{
|
<span v-else-if="props.entity.kind === 'company'">{{
|
||||||
trans(THIRDPARTY_A_CONTACT)
|
trans(THIRDPARTY_A_COMPANY)
|
||||||
}}</span>
|
}}</span>
|
||||||
<span v-else>{{ $t("thirdparty.contact") }}</span>
|
<span v-else>{{ trans(THIRDPARTY_A_CONTACT) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@@ -54,6 +54,7 @@ import {
|
|||||||
ACCEPTED_USERS,
|
ACCEPTED_USERS,
|
||||||
THIRDPARTY_A_CONTACT,
|
THIRDPARTY_A_CONTACT,
|
||||||
THIRDPARTY_CONTACT_OF,
|
THIRDPARTY_CONTACT_OF,
|
||||||
|
THIRDPARTY_A_COMPANY,
|
||||||
PERSON,
|
PERSON,
|
||||||
THIRDPARTY,
|
THIRDPARTY,
|
||||||
} from "translator";
|
} from "translator";
|
||||||
|
@@ -1,214 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a
|
|
||||||
v-if="isOpenDocument"
|
|
||||||
class="btn"
|
|
||||||
:class="[
|
|
||||||
isChangeIcon ? 'change-icon' : '',
|
|
||||||
isChangeClass ? options.changeClass : 'btn-wopilink',
|
|
||||||
]"
|
|
||||||
@click="openModal"
|
|
||||||
>
|
|
||||||
<i v-if="isChangeIcon" class="fa me-2" :class="options.changeIcon"></i>
|
|
||||||
|
|
||||||
<span v-if="!noText">
|
|
||||||
{{ trans(WOPI_ONLINE_EDIT_DOCUMENT) }}
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<teleport to="body">
|
|
||||||
<div class="wopi-frame" v-if="isOpenDocument">
|
|
||||||
<modal
|
|
||||||
v-if="modal.showModal"
|
|
||||||
:modalDialogClass="modal.modalDialogClass"
|
|
||||||
:hideFooter="true"
|
|
||||||
@close="modal.showModal = false"
|
|
||||||
>
|
|
||||||
<template #header>
|
|
||||||
<img class="logo" :src="logo" height="45" />
|
|
||||||
<span class="ms-auto me-3">
|
|
||||||
<span v-if="options.title">{{ options.title }}</span>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #body>
|
|
||||||
<div v-if="loading" class="loading">
|
|
||||||
<i
|
|
||||||
class="fa fa-circle-o-notch fa-spin fa-3x"
|
|
||||||
:title="trans(WOPI_LOADING)"
|
|
||||||
></i>
|
|
||||||
</div>
|
|
||||||
<iframe :src="this.wopiUrl" @load="loaded"></iframe>
|
|
||||||
</template>
|
|
||||||
</modal>
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<Modal
|
|
||||||
v-if="modal.showModal"
|
|
||||||
modalDialogClass="modal-sm"
|
|
||||||
@close="modal.showModal = false"
|
|
||||||
>
|
|
||||||
<template v-slot:header>
|
|
||||||
<h3>{{ trans(WOPI_INVALID_TITLE) }}</h3>
|
|
||||||
</template>
|
|
||||||
<template v-slot:body>
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
{{ trans(WOPI_ONLINE_EDIT_DOCUMENT) }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
</teleport>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, computed } from "vue";
|
|
||||||
import {
|
|
||||||
trans,
|
|
||||||
WOPI_ONLINE_EDIT_DOCUMENT,
|
|
||||||
WOPI_INVALID_TITLE,
|
|
||||||
WOPI_LOADING,
|
|
||||||
} from "translator";
|
|
||||||
import Modal from "ChillMainAssets/vuejs/_components/Modal";
|
|
||||||
import logo from "ChillMainAssets/chill/img/logo-chill-sans-slogan_white.png";
|
|
||||||
|
|
||||||
// Props
|
|
||||||
const props = defineProps({
|
|
||||||
wopiUrl: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
type: Object,
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// data
|
|
||||||
const modal = ref({
|
|
||||||
showModal: false,
|
|
||||||
modalDialogClass: "modal-fullscreen",
|
|
||||||
});
|
|
||||||
const loading = ref(false);
|
|
||||||
|
|
||||||
// MIME types
|
|
||||||
const mime = [
|
|
||||||
// TODO temporary hardcoded. to be replaced by twig extension or a collabora server query
|
|
||||||
"application/clarisworks",
|
|
||||||
"application/coreldraw",
|
|
||||||
"application/macwriteii",
|
|
||||||
"application/msword",
|
|
||||||
"application/pdf",
|
|
||||||
"application/vnd.lotus-1-2-3",
|
|
||||||
"application/vnd.ms-excel",
|
|
||||||
"application/vnd.ms-excel.sheet.binary.macroEnabled.12",
|
|
||||||
"application/vnd.ms-excel.sheet.macroEnabled.12",
|
|
||||||
"application/vnd.ms-excel.template.macroEnabled.12",
|
|
||||||
"application/vnd.ms-powerpoint",
|
|
||||||
"application/vnd.ms-powerpoint.presentation.macroEnabled.12",
|
|
||||||
"application/vnd.ms-powerpoint.template.macroEnabled.12",
|
|
||||||
"application/vnd.ms-visio.drawing",
|
|
||||||
"application/vnd.ms-word.document.macroEnabled.12",
|
|
||||||
"application/vnd.ms-word.template.macroEnabled.12",
|
|
||||||
"application/vnd.ms-works",
|
|
||||||
"application/vnd.oasis.opendocument.chart",
|
|
||||||
"application/vnd.oasis.opendocument.formula",
|
|
||||||
"application/vnd.oasis.opendocument.graphics",
|
|
||||||
"application/vnd.oasis.opendocument.graphics-flat-xml",
|
|
||||||
"application/vnd.oasis.opendocument.graphics-template",
|
|
||||||
"application/vnd.oasis.opendocument.presentation",
|
|
||||||
"application/vnd.oasis.opendocument.presentation-flat-xml",
|
|
||||||
"application/vnd.oasis.opendocument.presentation-template",
|
|
||||||
"application/vnd.oasis.opendocument.spreadsheet",
|
|
||||||
"application/vnd.oasis.opendocument.spreadsheet-flat-xml",
|
|
||||||
"application/vnd.oasis.opendocument.spreadsheet-template",
|
|
||||||
"application/vnd.oasis.opendocument.text",
|
|
||||||
"application/vnd.oasis.opendocument.text-flat-xml",
|
|
||||||
"application/vnd.oasis.opendocument.text-master",
|
|
||||||
"application/vnd.oasis.opendocument.text-master-template",
|
|
||||||
"application/vnd.oasis.opendocument.text-template",
|
|
||||||
"application/vnd.oasis.opendocument.text-web",
|
|
||||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
||||||
"application/vnd.openxmlformats-officedocument.presentationml.slideshow",
|
|
||||||
"application/vnd.openxmlformats-officedocument.presentationml.template",
|
|
||||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
||||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.template",
|
|
||||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
||||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.template",
|
|
||||||
"application/vnd.sun.xml.calc",
|
|
||||||
"application/vnd.sun.xml.calc.template",
|
|
||||||
"application/vnd.sun.xml.chart",
|
|
||||||
"application/vnd.sun.xml.draw",
|
|
||||||
"application/vnd.sun.xml.draw.template",
|
|
||||||
"application/vnd.sun.xml.impress",
|
|
||||||
"application/vnd.sun.xml.impress.template",
|
|
||||||
"application/vnd.sun.xml.math",
|
|
||||||
"application/vnd.sun.xml.writer",
|
|
||||||
"application/vnd.sun.xml.writer.global",
|
|
||||||
"application/vnd.sun.xml.writer.template",
|
|
||||||
"application/vnd.visio",
|
|
||||||
"application/vnd.visio2013",
|
|
||||||
"application/vnd.wordperfect",
|
|
||||||
"application/x-abiword",
|
|
||||||
"application/x-aportisdoc",
|
|
||||||
"application/x-dbase",
|
|
||||||
"application/x-dif-document",
|
|
||||||
"application/x-fictionbook+xml",
|
|
||||||
"application/x-gnumeric",
|
|
||||||
"application/x-hwp",
|
|
||||||
"application/x-iwork-keynote-sffkey",
|
|
||||||
"application/x-iwork-numbers-sffnumbers",
|
|
||||||
"application/x-iwork-pages-sffpages",
|
|
||||||
"application/x-mspublisher",
|
|
||||||
"application/x-mswrite",
|
|
||||||
"application/x-pagemaker",
|
|
||||||
"application/x-sony-bbeb",
|
|
||||||
"application/x-t602",
|
|
||||||
];
|
|
||||||
|
|
||||||
// Computed
|
|
||||||
const isOpenDocument = computed(() => mime.includes(props.type));
|
|
||||||
|
|
||||||
const noText = computed(() => props.options?.noText === true);
|
|
||||||
|
|
||||||
const isChangeIcon = computed(() => !!props.options?.changeIcon);
|
|
||||||
|
|
||||||
const isChangeClass = computed(() => !!props.options?.changeClass);
|
|
||||||
|
|
||||||
// Methods
|
|
||||||
const openModal = () => {
|
|
||||||
loading.value = true;
|
|
||||||
modal.value.showModal = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const loaded = () => {
|
|
||||||
loading.value = false;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
div.wopi-frame {
|
|
||||||
div.modal-header {
|
|
||||||
border-bottom: 0;
|
|
||||||
background-color: var(--bs-primary);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
div.modal-body {
|
|
||||||
padding: 0;
|
|
||||||
overflow-y: unset !important;
|
|
||||||
iframe {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
div.loading {
|
|
||||||
position: absolute;
|
|
||||||
color: var(--bs-chill-gray);
|
|
||||||
top: calc(50% - 30px);
|
|
||||||
left: calc(50% - 30px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@@ -54,6 +54,11 @@ const messages = {
|
|||||||
residential_address: "Adresse de résidence",
|
residential_address: "Adresse de résidence",
|
||||||
located_at: "réside chez",
|
located_at: "réside chez",
|
||||||
},
|
},
|
||||||
|
comment: {
|
||||||
|
label: "Commentaire",
|
||||||
|
editor_simple: "Simple",
|
||||||
|
editor_rich: "Riche"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -136,6 +136,59 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h2>Fix the title in the flex table</h2>
|
||||||
|
|
||||||
|
<p>This will fix the layout of the row, with a "title" element, and an aside element. Using <code>css grid</code>, this is quite safe and won't overflow</p>
|
||||||
|
|
||||||
|
<xmp>
|
||||||
|
<div class="flex-table">
|
||||||
|
<div class="item-bloc">
|
||||||
|
<div class="item-row">
|
||||||
|
<div class="item-two-col-grid">
|
||||||
|
<div class="title">This is my title</div>
|
||||||
|
<div class="aside">Aside value</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="item-bloc">
|
||||||
|
<div class="item-row">
|
||||||
|
<div class="item-two-col-grid">
|
||||||
|
<div class="title">
|
||||||
|
<div><h3>This is my title, which can be very long and take a lot of place. But it is wrapped successfully, and won't disturb the placement of the aside block</h3></div>
|
||||||
|
<div>This is a second line</div>
|
||||||
|
</div>
|
||||||
|
<div class="aside">Aside value</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</xmp>
|
||||||
|
|
||||||
|
<p>will render:</p>
|
||||||
|
|
||||||
|
<div class="flex-table">
|
||||||
|
<div class="item-bloc">
|
||||||
|
<div class="item-row">
|
||||||
|
<div class="item-two-col-grid">
|
||||||
|
<div class="title">This is my title</div>
|
||||||
|
<div class="aside">Aside value</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="item-bloc">
|
||||||
|
<div class="item-row">
|
||||||
|
<div class="item-two-col-grid">
|
||||||
|
<div class="title">
|
||||||
|
<div><h3>This is my title, which can be very long and take a lot of place. But it is wrapped successfully, and won't disturb the placement of the aside block</h3></div>
|
||||||
|
<div>This is a second line</div>
|
||||||
|
</div>
|
||||||
|
<div class="aside">Aside value</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<h2>Wrap-list</h2>
|
<h2>Wrap-list</h2>
|
||||||
<p>Une liste inline qui s'aligne, puis glisse sous son titre.</p>
|
<p>Une liste inline qui s'aligne, puis glisse sous son titre.</p>
|
||||||
<div class="wrap-list debug">
|
<div class="wrap-list debug">
|
||||||
@@ -392,4 +445,12 @@ Toutes les classes btn-* de bootstrap sont fonctionnelles
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<h1>Badges</h1>
|
||||||
|
|
||||||
|
<span class="badge-accompanying-work-type-simple">Action d'accompagnement</span>
|
||||||
|
<span class="badge-activity-type-simple">Type d'échange</span>
|
||||||
|
<span class="badge-calendar-simple">Rendez-vous</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -214,7 +214,9 @@
|
|||||||
|
|
||||||
{% block private_comment_widget %}
|
{% block private_comment_widget %}
|
||||||
{% for entry in form %}
|
{% for entry in form %}
|
||||||
{{ form_widget(entry) }}
|
<div id="comment-app-{{ form.vars.id }}" data-field-name="{{ form.vars.full_name }}">
|
||||||
|
{{ form_widget(entry, { attr: { ckeditor: 'true' } }) }}
|
||||||
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -224,7 +226,9 @@
|
|||||||
|
|
||||||
{% block comment_widget %}
|
{% block comment_widget %}
|
||||||
{% for entry in form %}
|
{% for entry in form %}
|
||||||
{{ form_widget(entry) }}
|
<div id="comment-app-{{ form.vars.id }}" data-field-name="{{ form.vars.full_name }}">
|
||||||
|
{{ form_widget(entry, { attr: { ckeditor: 'true' } }) }}
|
||||||
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endblock comment_widget %}
|
{% endblock comment_widget %}
|
||||||
|
|
||||||
|
@@ -9,7 +9,6 @@
|
|||||||
{{ encore_entry_script_tags('mod_pickentity_type') }}
|
{{ encore_entry_script_tags('mod_pickentity_type') }}
|
||||||
{{ encore_entry_script_tags('mod_entity_workflow_subscribe') }}
|
{{ encore_entry_script_tags('mod_entity_workflow_subscribe') }}
|
||||||
{{ encore_entry_script_tags('page_workflow_show') }}
|
{{ encore_entry_script_tags('page_workflow_show') }}
|
||||||
{{ encore_entry_script_tags('mod_wopi_link') }}
|
|
||||||
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
|
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
|
||||||
{{ encore_entry_script_tags('mod_workflow_attachment') }}
|
{{ encore_entry_script_tags('mod_workflow_attachment') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -19,7 +18,6 @@
|
|||||||
{{ encore_entry_link_tags('mod_pickentity_type') }}
|
{{ encore_entry_link_tags('mod_pickentity_type') }}
|
||||||
{{ encore_entry_link_tags('mod_entity_workflow_subscribe') }}
|
{{ encore_entry_link_tags('mod_entity_workflow_subscribe') }}
|
||||||
{{ encore_entry_link_tags('page_workflow_show') }}
|
{{ encore_entry_link_tags('page_workflow_show') }}
|
||||||
{{ encore_entry_link_tags('mod_wopi_link') }}
|
|
||||||
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
|
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
|
||||||
{{ encore_entry_link_tags('mod_workflow_attachment') }}
|
{{ encore_entry_link_tags('mod_workflow_attachment') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -25,6 +25,8 @@ use Symfony\Component\Workflow\Transition;
|
|||||||
#[AsMessageHandler]
|
#[AsMessageHandler]
|
||||||
final readonly class CancelStaleWorkflowHandler
|
final readonly class CancelStaleWorkflowHandler
|
||||||
{
|
{
|
||||||
|
private const LOG_PREFIX = '[CancelStaleWorkflowHandler] ';
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private EntityWorkflowRepository $workflowRepository,
|
private EntityWorkflowRepository $workflowRepository,
|
||||||
private Registry $registry,
|
private Registry $registry,
|
||||||
@@ -40,13 +42,13 @@ final readonly class CancelStaleWorkflowHandler
|
|||||||
|
|
||||||
$workflow = $this->workflowRepository->find($message->getWorkflowId());
|
$workflow = $this->workflowRepository->find($message->getWorkflowId());
|
||||||
if (null === $workflow) {
|
if (null === $workflow) {
|
||||||
$this->logger->alert('Workflow was not found!', [$workflowId]);
|
$this->logger->alert(self::LOG_PREFIX.'Workflow was not found!', ['entityWorkflowId' => $workflowId]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (false === $workflow->isStaledAt($olderThanDate)) {
|
if (false === $workflow->isStaledAt($olderThanDate)) {
|
||||||
$this->logger->alert('Workflow has transitioned in the meantime.', [$workflowId]);
|
$this->logger->alert(self::LOG_PREFIX.'Workflow has transitioned in the meantime.', ['entityWorkflowId' => $workflowId]);
|
||||||
|
|
||||||
throw new UnrecoverableMessageHandlingException('the workflow is not staled any more');
|
throw new UnrecoverableMessageHandlingException('the workflow is not staled any more');
|
||||||
}
|
}
|
||||||
@@ -67,14 +69,14 @@ final readonly class CancelStaleWorkflowHandler
|
|||||||
'transitionAt' => $this->clock->now(),
|
'transitionAt' => $this->clock->now(),
|
||||||
'transition' => $transition->getName(),
|
'transition' => $transition->getName(),
|
||||||
]);
|
]);
|
||||||
$this->logger->info('EntityWorkflow has been cancelled automatically.', [$workflowId]);
|
$this->logger->info(self::LOG_PREFIX.'EntityWorkflow has been cancelled automatically.', ['entityWorkflowId' => $workflowId]);
|
||||||
$transitionApplied = true;
|
$transitionApplied = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$transitionApplied) {
|
if (!$transitionApplied) {
|
||||||
$this->logger->error('No valid transition found for EntityWorkflow.', [$workflowId]);
|
$this->logger->error(self::LOG_PREFIX.'No valid transition found for EntityWorkflow.', ['entityWorkflowId' => $workflowId]);
|
||||||
throw new UnrecoverableMessageHandlingException(sprintf('No valid transition found for EntityWorkflow %d.', $workflowId));
|
throw new UnrecoverableMessageHandlingException(sprintf('No valid transition found for EntityWorkflow %d.', $workflowId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -86,10 +86,6 @@ module.exports = function (encore, entries) {
|
|||||||
"mod_entity_workflow_pick",
|
"mod_entity_workflow_pick",
|
||||||
__dirname + "/Resources/public/module/entity-workflow-pick/index.js",
|
__dirname + "/Resources/public/module/entity-workflow-pick/index.js",
|
||||||
);
|
);
|
||||||
encore.addEntry(
|
|
||||||
"mod_wopi_link",
|
|
||||||
__dirname + "/Resources/public/module/wopi-link/index.js",
|
|
||||||
);
|
|
||||||
encore.addEntry(
|
encore.addEntry(
|
||||||
"mod_pick_postal_code",
|
"mod_pick_postal_code",
|
||||||
__dirname + "/Resources/public/module/pick-postal-code/index.js",
|
__dirname + "/Resources/public/module/pick-postal-code/index.js",
|
||||||
|
@@ -59,6 +59,7 @@ user_group:
|
|||||||
inactive: Inactif
|
inactive: Inactif
|
||||||
with_users: Membres
|
with_users: Membres
|
||||||
no_users: Aucun utilisateur associé
|
no_users: Aucun utilisateur associé
|
||||||
|
no_user_groups: Aucune groupe d'utilisateurs
|
||||||
no_admin_users: Aucun administrateur
|
no_admin_users: Aucun administrateur
|
||||||
Label: Nom du groupe
|
Label: Nom du groupe
|
||||||
BackgroundColor: Couleur de fond du badge
|
BackgroundColor: Couleur de fond du badge
|
||||||
@@ -112,6 +113,8 @@ Any comment: Aucun commentaire
|
|||||||
# comment embeddable
|
# comment embeddable
|
||||||
No comment associated: Aucun commentaire
|
No comment associated: Aucun commentaire
|
||||||
private comment: Notes privées
|
private comment: Notes privées
|
||||||
|
comment_public: Note
|
||||||
|
comment_private: Note privée
|
||||||
|
|
||||||
#pagination
|
#pagination
|
||||||
Previous: Précédent
|
Previous: Précédent
|
||||||
@@ -739,6 +742,7 @@ export:
|
|||||||
id: Identifiant de l'action
|
id: Identifiant de l'action
|
||||||
social_issue_id: Identifiant de la problématique sociale
|
social_issue_id: Identifiant de la problématique sociale
|
||||||
social_issue: Problématique sociale
|
social_issue: Problématique sociale
|
||||||
|
desactivation_date: Date de désactivation
|
||||||
social_issue_ordering: Ordre de la problématique sociale
|
social_issue_ordering: Ordre de la problématique sociale
|
||||||
action_label: Action d'accompagnement
|
action_label: Action d'accompagnement
|
||||||
action_ordering: Ordre
|
action_ordering: Ordre
|
||||||
|
@@ -26,7 +26,7 @@ readonly class AccompanyingPeriodStepChangeCronjob implements CronJobInterface
|
|||||||
{
|
{
|
||||||
$now = $this->clock->now();
|
$now = $this->clock->now();
|
||||||
|
|
||||||
if (null !== $cronJobExecution && $now->sub(new \DateInterval('P1D')) < $cronJobExecution->getLastStart()) {
|
if (null !== $cronJobExecution && $now->sub(new \DateInterval('PT23H45M')) < $cronJobExecution->getLastStart()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -204,20 +204,24 @@ final class AccompanyingCourseController extends \Symfony\Bundle\FrameworkBundle
|
|||||||
['date' => 'DESC', 'id' => 'DESC'],
|
['date' => 'DESC', 'id' => 'DESC'],
|
||||||
);
|
);
|
||||||
|
|
||||||
$activities = \array_slice($activities, 0, 3);
|
|
||||||
|
|
||||||
$works = $this->workRepository->findByAccompanyingPeriod(
|
$works = $this->workRepository->findByAccompanyingPeriod(
|
||||||
$accompanyingCourse,
|
$accompanyingCourse,
|
||||||
['startDate' => 'DESC', 'endDate' => 'DESC'],
|
['startDate' => 'DESC', 'endDate' => 'DESC'],
|
||||||
3
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$counters = [
|
||||||
|
'activities' => count($activities),
|
||||||
|
'openWorks' => count($accompanyingCourse->getOpenWorks()),
|
||||||
|
'works' => count($works),
|
||||||
|
];
|
||||||
|
|
||||||
return $this->render('@ChillPerson/AccompanyingCourse/index.html.twig', [
|
return $this->render('@ChillPerson/AccompanyingCourse/index.html.twig', [
|
||||||
'accompanyingCourse' => $accompanyingCourse,
|
'accompanyingCourse' => $accompanyingCourse,
|
||||||
'withoutHousehold' => $withoutHousehold,
|
'withoutHousehold' => $withoutHousehold,
|
||||||
'participationsByHousehold' => $accompanyingCourse->actualParticipationsByHousehold(),
|
'participationsByHousehold' => $accompanyingCourse->actualParticipationsByHousehold(),
|
||||||
'works' => $works,
|
'works' => \array_slice($works, 0, 3),
|
||||||
'activities' => $activities,
|
'activities' => \array_slice($activities, 0, 3),
|
||||||
|
'counters' => $counters,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -511,6 +511,14 @@ class AccompanyingPeriod implements
|
|||||||
return $this->getParticipationsContainsPerson($person)->count() > 0;
|
return $this->getParticipationsContainsPerson($person)->count() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getOpenWorks(): Collection
|
||||||
|
{
|
||||||
|
return $this->getWorks()->filter(
|
||||||
|
static fn (AccompanyingPeriodWork $work): bool => null === $work->getEndDate()
|
||||||
|
or $work->getEndDate() > new \DateTimeImmutable('today')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a new participation for a person.
|
* Open a new participation for a person.
|
||||||
*/
|
*/
|
||||||
|
@@ -58,13 +58,11 @@ class HouseholdComposition implements TrackCreationInterface, TrackUpdateInterfa
|
|||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, nullable: true, options: ['default' => null])]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, nullable: true, options: ['default' => null])]
|
||||||
private ?int $numberOfChildren = null;
|
private ?int $numberOfChildren = null;
|
||||||
|
|
||||||
#[Assert\NotNull]
|
|
||||||
#[Assert\GreaterThanOrEqual(0, groups: ['Default', 'household_composition'])]
|
#[Assert\GreaterThanOrEqual(0, groups: ['Default', 'household_composition'])]
|
||||||
#[Serializer\Groups(['docgen:read'])]
|
#[Serializer\Groups(['docgen:read'])]
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, nullable: true, options: ['default' => null])]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, nullable: true, options: ['default' => null])]
|
||||||
private ?int $numberOfDependents = null;
|
private ?int $numberOfDependents = null;
|
||||||
|
|
||||||
#[Assert\NotNull]
|
|
||||||
#[Assert\GreaterThanOrEqual(0, groups: ['Default', 'household_composition'])]
|
#[Assert\GreaterThanOrEqual(0, groups: ['Default', 'household_composition'])]
|
||||||
#[Serializer\Groups(['docgen:read'])]
|
#[Serializer\Groups(['docgen:read'])]
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, nullable: true, options: ['default' => null])]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, nullable: true, options: ['default' => null])]
|
||||||
|
@@ -22,7 +22,7 @@ use Doctrine\ORM\Mapping as ORM;
|
|||||||
class MaritalStatus
|
class MaritalStatus
|
||||||
{
|
{
|
||||||
#[ORM\Id]
|
#[ORM\Id]
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 7)]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 15)]
|
||||||
private ?string $id;
|
private ?string $id;
|
||||||
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON)]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON)]
|
||||||
|
@@ -71,7 +71,7 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
->setExtras(['order' => 30]);
|
->setExtras(['order' => 30]);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$menu->addChild($this->translator->trans('Accompanying Course Comment'), [
|
$menu->addChild($this->translator->trans('Accompanying Course Comments'), [
|
||||||
'route' => 'chill_person_accompanying_period_comment_list',
|
'route' => 'chill_person_accompanying_period_comment_list',
|
||||||
'routeParameters' => [
|
'routeParameters' => [
|
||||||
'accompanying_period_id' => $period->getId(),
|
'accompanying_period_id' => $period->getId(),
|
||||||
@@ -80,12 +80,15 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->security->isGranted(AccompanyingPeriodWorkVoter::SEE, $period)) {
|
if ($this->security->isGranted(AccompanyingPeriodWorkVoter::SEE, $period)) {
|
||||||
$menu->addChild($this->translator->trans('Accompanying Course Action'), [
|
$menu->addChild($this->translator->trans('Accompanying Course Actions'), [
|
||||||
'route' => 'chill_person_accompanying_period_work_list',
|
'route' => 'chill_person_accompanying_period_work_list',
|
||||||
'routeParameters' => [
|
'routeParameters' => [
|
||||||
'id' => $period->getId(),
|
'id' => $period->getId(),
|
||||||
], ])
|
], ])
|
||||||
->setExtras(['order' => 40]);
|
->setExtras([
|
||||||
|
'order' => 40,
|
||||||
|
'counter' => count($period->getWorks()) > 0 ? count($period->getWorks()) : null,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$workflow = $this->registry->get($period, 'accompanying_period_lifecycle');
|
$workflow = $this->registry->get($period, 'accompanying_period_lifecycle');
|
||||||
|
@@ -304,5 +304,14 @@ div#dashboards {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
div.count-item {
|
||||||
|
font-size: 3rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
div.count-item-label {
|
||||||
|
font-size: 90%;
|
||||||
|
font-variant: all-small-caps;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge-accompanying-work-type-simple {
|
||||||
|
@extend .badge;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0.2rem 0;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0.5rem;
|
||||||
|
|
||||||
|
border-left: 20px groove $orange;
|
||||||
|
border-radius: $badge-border-radius;
|
||||||
|
|
||||||
|
max-width: 100%;
|
||||||
|
background-color: $gray-100;
|
||||||
|
|
||||||
|
color: black;
|
||||||
|
font-weight: normal;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
text-indent: 5px hanging;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
margin-right: 3px;
|
||||||
|
position: relative;
|
||||||
|
left: -0.5px;
|
||||||
|
font-family: ForkAwesome;
|
||||||
|
content: '\f04b';
|
||||||
|
color: #e2793d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// AccompanyingCourse Work Pages
|
/// AccompanyingCourse Work Pages
|
||||||
div.accompanying-course-work {
|
div.accompanying-course-work {
|
||||||
|
|
||||||
|
@@ -61,15 +61,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ClassicEditor } from "ckeditor5";
|
import {ClassicEditor} from "ckeditor5";
|
||||||
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
|
import {Ckeditor} from "@ckeditor/ckeditor5-vue";
|
||||||
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
|
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
|
||||||
import { mapState } from "vuex";
|
import { mapState } from "vuex";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Comment",
|
name: "Comment",
|
||||||
components: {
|
components: {
|
||||||
ckeditor: Ckeditor,
|
ckeditor: Ckeditor
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@@ -204,7 +204,8 @@ export default {
|
|||||||
} else if (payload.type === "thirdparty") {
|
} else if (payload.type === "thirdparty") {
|
||||||
body.name = payload.data.text;
|
body.name = payload.data.text;
|
||||||
body.email = payload.data.email;
|
body.email = payload.data.email;
|
||||||
body.telephone = payload.data.phonenumber;
|
body.telephone = payload.data.telephone;
|
||||||
|
body.telephone2 = payload.data.telephone2;
|
||||||
body.address = { id: payload.data.address.address_id };
|
body.address = { id: payload.data.address.address_id };
|
||||||
|
|
||||||
makeFetch(
|
makeFetch(
|
||||||
|
@@ -385,7 +385,8 @@ export default {
|
|||||||
} else if (payload.type === "thirdparty") {
|
} else if (payload.type === "thirdparty") {
|
||||||
body.name = payload.data.text;
|
body.name = payload.data.text;
|
||||||
body.email = payload.data.email;
|
body.email = payload.data.email;
|
||||||
body.telephone = payload.data.phonenumber;
|
body.telephone = payload.data.telephone;
|
||||||
|
body.telephone2 = payload.data.telephone2;
|
||||||
if (payload.data.address) {
|
if (payload.data.address) {
|
||||||
body.address = { id: payload.data.address.address_id };
|
body.address = { id: payload.data.address.address_id };
|
||||||
}
|
}
|
||||||
|
@@ -194,6 +194,7 @@ export default {
|
|||||||
body.name = payload.data.name;
|
body.name = payload.data.name;
|
||||||
body.email = payload.data.email;
|
body.email = payload.data.email;
|
||||||
body.telephone = payload.data.telephone;
|
body.telephone = payload.data.telephone;
|
||||||
|
body.telephone2 = payload.data.telephone2;
|
||||||
body.address = payload.data.address
|
body.address = payload.data.address
|
||||||
? { id: payload.data.address.address_id }
|
? { id: payload.data.address.address_id }
|
||||||
: null;
|
: null;
|
||||||
|
@@ -39,15 +39,15 @@
|
|||||||
<script>
|
<script>
|
||||||
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
|
import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
|
||||||
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
|
||||||
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
|
import { Ckeditor }from "@ckeditor/ckeditor5-vue";
|
||||||
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
|
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
|
||||||
import { ClassicEditor } from "ckeditor5";
|
import {ClassicEditor} from "ckeditor5";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "WriteComment",
|
name: "WriteComment",
|
||||||
components: {
|
components: {
|
||||||
Modal,
|
Modal,
|
||||||
ckeditor: Ckeditor,
|
ckeditor: Ckeditor
|
||||||
},
|
},
|
||||||
props: ["resource"],
|
props: ["resource"],
|
||||||
emits: ["updateComment"],
|
emits: ["updateComment"],
|
||||||
|
@@ -46,8 +46,7 @@
|
|||||||
<label class="col-form-label">{{ $t("comments") }}</label>
|
<label class="col-form-label">{{ $t("comments") }}</label>
|
||||||
<ckeditor
|
<ckeditor
|
||||||
v-model="note"
|
v-model="note"
|
||||||
:editor="classicEditor"
|
:editor="classicEditor" :config="editorConfig"
|
||||||
:config="editorConfig"
|
|
||||||
tag-name="textarea"
|
tag-name="textarea"
|
||||||
></ckeditor>
|
></ckeditor>
|
||||||
</div>
|
</div>
|
||||||
@@ -208,6 +207,29 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
<li
|
||||||
|
v-for="p in getPreviousPersons"
|
||||||
|
:key="p.id"
|
||||||
|
class="alert alert-danger"
|
||||||
|
>
|
||||||
|
<div class="form-check">
|
||||||
|
<input
|
||||||
|
v-model="personsPicked"
|
||||||
|
:value="p.id"
|
||||||
|
type="checkbox"
|
||||||
|
class="me-2 form-check-input"
|
||||||
|
:id="'person_check' + p.id"
|
||||||
|
/>
|
||||||
|
<label :for="'person_check' + p.id" class="form-check-label">
|
||||||
|
<person-text :person="p"></person-text>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
><i class="fa fa-warning"></i> {{
|
||||||
|
$t("warning_previous_persons")
|
||||||
|
}}</span
|
||||||
|
>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -440,7 +462,7 @@
|
|||||||
import { mapState, mapGetters } from "vuex";
|
import { mapState, mapGetters } from "vuex";
|
||||||
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
|
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
|
||||||
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
|
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
|
||||||
import { ClassicEditor } from "ckeditor5";
|
import {ClassicEditor} from "ckeditor5";
|
||||||
import AddResult from "./components/AddResult.vue";
|
import AddResult from "./components/AddResult.vue";
|
||||||
import AddEvaluation from "./components/AddEvaluation.vue";
|
import AddEvaluation from "./components/AddEvaluation.vue";
|
||||||
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
|
import AddPersons from "ChillPersonAssets/vuejs/_components/AddPersons.vue";
|
||||||
@@ -497,6 +519,8 @@ const i18n = {
|
|||||||
notification_notify_referrer: "Notifier le référent",
|
notification_notify_referrer: "Notifier le référent",
|
||||||
notification_notify_any: "Notifier d'autres utilisateurs",
|
notification_notify_any: "Notifier d'autres utilisateurs",
|
||||||
notification_send: "Envoyer une notification",
|
notification_send: "Envoyer une notification",
|
||||||
|
warning_previous_persons:
|
||||||
|
"Cet usager n'est désormais plus concerné par le parcours, bien qu'il ait été associé à l'action par le passé.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -583,6 +607,7 @@ export default {
|
|||||||
"hasHandlingThirdParty",
|
"hasHandlingThirdParty",
|
||||||
"hasThirdParties",
|
"hasThirdParties",
|
||||||
"hasReferrers",
|
"hasReferrers",
|
||||||
|
"getPreviousPersons",
|
||||||
]),
|
]),
|
||||||
classicEditor: () => ClassicEditor,
|
classicEditor: () => ClassicEditor,
|
||||||
editorConfig: () => classicEditorConfig,
|
editorConfig: () => classicEditorConfig,
|
||||||
@@ -745,7 +770,8 @@ export default {
|
|||||||
let body = { type: payload.type };
|
let body = { type: payload.type };
|
||||||
body.name = payload.data.text;
|
body.name = payload.data.text;
|
||||||
body.email = payload.data.email;
|
body.email = payload.data.email;
|
||||||
body.telephone = payload.data.phonenumber;
|
body.telephone = payload.data.telephone;
|
||||||
|
body.telephone2 = payload.data.telephone2;
|
||||||
body.address = { id: payload.data.address.address_id };
|
body.address = { id: payload.data.address.address_id };
|
||||||
|
|
||||||
makeFetch(
|
makeFetch(
|
||||||
@@ -755,7 +781,9 @@ export default {
|
|||||||
)
|
)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
this.$store.dispatch("updateThirdParty", response);
|
this.$store.dispatch("updateThirdParty", response);
|
||||||
this.$refs.onTheFly.closeModal();
|
for (let otf of this.$refs.onTheFly) {
|
||||||
|
otf.closeModal();
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
if (error.name === "ValidationException") {
|
if (error.name === "ValidationException") {
|
||||||
|
@@ -273,7 +273,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ISOToDatetime } from "ChillMainAssets/chill/js/date";
|
import { ISOToDatetime } from "ChillMainAssets/chill/js/date";
|
||||||
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
|
import {Ckeditor} from "@ckeditor/ckeditor5-vue";
|
||||||
import { ClassicEditor } from "ckeditor5";
|
import { ClassicEditor } from "ckeditor5";
|
||||||
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
|
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
|
||||||
import { mapState } from "vuex";
|
import { mapState } from "vuex";
|
||||||
@@ -535,11 +535,11 @@ export default {
|
|||||||
title: title,
|
title: title,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
addDocument({ stored_object, stored_object_version }) {
|
addDocument({ stored_object, stored_object_version, file_name }) {
|
||||||
let document = {
|
let document = {
|
||||||
type: "accompanying_period_work_evaluation_document",
|
type: "accompanying_period_work_evaluation_document",
|
||||||
storedObject: stored_object,
|
storedObject: stored_object,
|
||||||
title: "Nouveau document",
|
title: file_name,
|
||||||
};
|
};
|
||||||
this.$store.commit("addDocument", {
|
this.$store.commit("addDocument", {
|
||||||
key: this.evaluation.key,
|
key: this.evaluation.key,
|
||||||
|
@@ -87,6 +87,11 @@ const store = createStore({
|
|||||||
|
|
||||||
return [];
|
return [];
|
||||||
},
|
},
|
||||||
|
getPreviousPersons(state) {
|
||||||
|
return state.personsPicked.filter(
|
||||||
|
(p) => !state.personsReachables.map((pr) => pr.id).includes(p.id),
|
||||||
|
);
|
||||||
|
},
|
||||||
buildPayload(state) {
|
buildPayload(state) {
|
||||||
return {
|
return {
|
||||||
type: "accompanying_period_work",
|
type: "accompanying_period_work",
|
||||||
@@ -607,8 +612,7 @@ const store = createStore({
|
|||||||
submit({ getters, state, commit }, callback) {
|
submit({ getters, state, commit }, callback) {
|
||||||
let payload = getters.buildPayload,
|
let payload = getters.buildPayload,
|
||||||
params = new URLSearchParams({ entity_version: state.version }),
|
params = new URLSearchParams({ entity_version: state.version }),
|
||||||
url = `/api/1.0/person/accompanying-course/work/${state.work.id}.json?${params}`,
|
url = `/api/1.0/person/accompanying-course/work/${state.work.id}.json?${params}`;
|
||||||
errors = [];
|
|
||||||
commit("setIsPosting", true);
|
commit("setIsPosting", true);
|
||||||
|
|
||||||
// console.log('the social action', payload);
|
// console.log('the social action', payload);
|
||||||
|
@@ -30,8 +30,7 @@
|
|||||||
|
|
||||||
<div class="item-row comment">
|
<div class="item-row comment">
|
||||||
<ckeditor
|
<ckeditor
|
||||||
:editor="classicEditor"
|
:editor="classicEditor" :config="editorConfig"
|
||||||
:config="editorConfig"
|
|
||||||
v-model="comment"
|
v-model="comment"
|
||||||
tag-name="textarea"
|
tag-name="textarea"
|
||||||
/>
|
/>
|
||||||
@@ -103,9 +102,9 @@ div.participation-details {
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from "vuex";
|
import { mapGetters } from "vuex";
|
||||||
import PersonRenderBox from "ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue";
|
import PersonRenderBox from "ChillPersonAssets/vuejs/_components/Entity/PersonRenderBox.vue";
|
||||||
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
|
import {Ckeditor} from "@ckeditor/ckeditor5-vue";
|
||||||
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
|
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
|
||||||
import { ClassicEditor } from "ckeditor5";
|
import {ClassicEditor} from "ckeditor5";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MemberDetails",
|
name: "MemberDetails",
|
||||||
|
@@ -1,25 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<ckeditor
|
<ckeditor
|
||||||
name="content"
|
name="content"
|
||||||
:placeholder="
|
:placeholder="
|
||||||
$t('household_members_editor.positioning.comment_placeholder')
|
$t('household_members_editor.positioning.comment_placeholder')
|
||||||
"
|
"
|
||||||
:editor="editor"
|
:editor="editor"
|
||||||
:config="editorConfig"
|
:config="editorConfig"
|
||||||
v-model="content"
|
v-model="content"
|
||||||
tag-name="textarea"
|
tag-name="textarea"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
|
import { Ckeditor } from "@ckeditor/ckeditor5-vue";
|
||||||
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
|
import classicEditorConfig from "ChillMainAssets/module/ckeditor5/editor_config";
|
||||||
import { ClassicEditor } from "ckeditor5";
|
import {ClassicEditor} from "ckeditor5";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PersonComment.vue",
|
name: "PersonComment.vue",
|
||||||
components: {
|
components: {
|
||||||
ckeditor: Ckeditor,
|
ckeditor: Ckeditor
|
||||||
},
|
},
|
||||||
props: ["conc"],
|
props: ["conc"],
|
||||||
computed: {
|
computed: {
|
||||||
|
@@ -201,7 +201,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if accompanyingCourse.step != 'DRAFT' %}
|
{% if accompanyingCourse.step != 'DRAFT' %}
|
||||||
<div class="mbloc col col-sm-6 col-lg-4">
|
<div class="mbloc col col-sm-6 col-lg-8 col-xxl-4">
|
||||||
<div class="notification-counter">
|
<div class="notification-counter">
|
||||||
<h4 class="item-key">{{ 'notification.Notifications'|trans }}</h4>
|
<h4 class="item-key">{{ 'notification.Notifications'|trans }}</h4>
|
||||||
{% set notif_counter = chill_count_notifications('Chill\\PersonBundle\\Entity\\AccompanyingPeriod', accompanyingCourse.id) %}
|
{% set notif_counter = chill_count_notifications('Chill\\PersonBundle\\Entity\\AccompanyingPeriod', accompanyingCourse.id) %}
|
||||||
@@ -238,6 +238,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if counters.activities > 0 %}
|
||||||
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="count-activities">
|
||||||
|
<div class="count-item">{{ counters.activities }}</div>
|
||||||
|
<div class="count-item-label">
|
||||||
|
{% if counters.activities == 1 %}
|
||||||
|
{{ 'Activity'|trans }}
|
||||||
|
{% else %}
|
||||||
|
{{ 'Activities'|trans }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if counters.works > 0 %}
|
||||||
|
<div class="mbloc col col-sm-6 col-lg-4">
|
||||||
|
<div class="count-works">
|
||||||
|
<div class="count-item">{{ counters.openWorks }} / {{ counters.works }}</div>
|
||||||
|
<div class="count-item-label">{{ 'accompanying_course_work.On-going works over total'|trans }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="social-actions my-4">
|
<div class="social-actions my-4">
|
||||||
|
@@ -8,7 +8,7 @@ L'usager {{ oldPersonLocation|chill_entity_render_string }} a déménagé.
|
|||||||
Son adresse était utilisée pour localiser le parcours n°{{ period.id }}, dont vous êtes
|
Son adresse était utilisée pour localiser le parcours n°{{ period.id }}, dont vous êtes
|
||||||
le référent.
|
le référent.
|
||||||
|
|
||||||
En conséquence de ce déménage, le parcours est toujours localisé à cette adresse, mais à l'aide d'une
|
En conséquence de ce déménagement, le parcours est toujours localisé à cette adresse, mais à l'aide d'une
|
||||||
adresse temporaire.
|
adresse temporaire.
|
||||||
|
|
||||||
Si vous continuez à suivre le parcours, vous pouvez le localiser à nouveau auprès de l'adresse de
|
Si vous continuez à suivre le parcours, vous pouvez le localiser à nouveau auprès de l'adresse de
|
||||||
|
@@ -5,44 +5,49 @@
|
|||||||
{% set w = document.accompanyingPeriodWorkEvaluation.accompanyingPeriodWork %}
|
{% set w = document.accompanyingPeriodWorkEvaluation.accompanyingPeriodWork %}
|
||||||
|
|
||||||
<div class="item-row">
|
<div class="item-row">
|
||||||
<div class="item-col" style="width: unset">
|
<!-- evaluation document -->
|
||||||
{% if document.storedObject.isPending %}
|
<div class="item-two-col-grid" style="width: unset">
|
||||||
<div class="badge text-bg-info" data-docgen-is-pending="{{ document.storedObject.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
|
<div class="title">
|
||||||
{% elseif document.storedObject.isFailure %}
|
{% if document.storedObject.isPending %}
|
||||||
<div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
|
<div class="badge text-bg-info" data-docgen-is-pending="{{ document.storedObject.id }}">{{ 'docgen.Doc generation is pending'|trans }}</div>
|
||||||
{% endif %}
|
{% elseif document.storedObject.isFailure %}
|
||||||
<div>
|
<div class="badge text-bg-warning">{{ 'docgen.Doc generation failed'|trans }}</div>
|
||||||
{% if context == 'person' %}
|
|
||||||
<span class="badge bg-primary">
|
|
||||||
<i class="fa fa-random"></i> {{ w.accompanyingPeriod.id }}
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="badge-accompanying-work-type">
|
|
||||||
<span class="title_label"></span>
|
|
||||||
<span class="title_action">{{ w.socialAction|chill_entity_render_string }} > {{ document.accompanyingPeriodWorkEvaluation.evaluation.title|localize_translatable_string }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="denomination h2">
|
|
||||||
{{ document.title|chill_print_or_message("No title") }}
|
|
||||||
</div>
|
|
||||||
{% if document.storedObject.type is not empty %}
|
|
||||||
<div>
|
<div>
|
||||||
{{ mm.mimeIcon(document.storedObject.type) }}
|
<div>
|
||||||
|
<div class="badge-accompanying-work-type-simple">
|
||||||
|
{{ w.socialAction|chill_entity_render_string }} > {{ document.accompanyingPeriodWorkEvaluation.evaluation.title|localize_translatable_string }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="denomination h2">
|
||||||
|
{{ document.title|chill_print_or_message("No title") }}
|
||||||
|
</div>
|
||||||
|
{% if document.storedObject.type is not empty %}
|
||||||
|
<div>
|
||||||
|
{{ mm.mimeIcon(document.storedObject.type) }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if document.storedObject.hasTemplate %}
|
||||||
|
<div>
|
||||||
|
<p>{{ document.storedObject.template.name|localize_translatable_string }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% if document.storedObject.createdAt is not null %}
|
||||||
|
<div class="aside">
|
||||||
|
<div class="dates row text-end">
|
||||||
|
<span>{{ document.storedObject.createdAt|format_date('short') }}</span>
|
||||||
|
</div>
|
||||||
|
{% if context == 'person' %}
|
||||||
|
<div class="text-end">
|
||||||
|
<span class="badge bg-primary">
|
||||||
|
<i class="fa fa-random"></i> {{ w.accompanyingPeriod.id }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if document.storedObject.hasTemplate %}
|
|
||||||
<div>
|
|
||||||
<p>{{ document.storedObject.template.name|localize_translatable_string }}</p>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="item-col">
|
|
||||||
<div class="container">
|
|
||||||
<div class="dates row text-end">
|
|
||||||
<span>{{ document.storedObject.createdAt|format_date('short') }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -30,9 +30,6 @@ final readonly class SocialActionCSVExportService
|
|||||||
private TranslatorInterface $translator,
|
private TranslatorInterface $translator,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param list<SocialAction> $actions
|
|
||||||
*/
|
|
||||||
public function generateCsv(array $actions): Writer
|
public function generateCsv(array $actions): Writer
|
||||||
{
|
{
|
||||||
// CSV headers
|
// CSV headers
|
||||||
@@ -84,7 +81,8 @@ final readonly class SocialActionCSVExportService
|
|||||||
'action_id' => $action->getId(),
|
'action_id' => $action->getId(),
|
||||||
'social_issue_id' => $action->getIssue()?->getId(),
|
'social_issue_id' => $action->getIssue()?->getId(),
|
||||||
'problematique_label' => null !== $action->getIssue() ? $this->socialIssueRender->renderString($action->getIssue(), []) : null,
|
'problematique_label' => null !== $action->getIssue() ? $this->socialIssueRender->renderString($action->getIssue(), []) : null,
|
||||||
'social_issue_ordering' => null !== $action->getIssue() ? $action->getIssue()->getOrdering() : null,
|
'desactivation_date' => $action->getDesactivationDate()?->format('Y-m-d'),
|
||||||
|
'social_issue_ordering' => $action->getIssue()?->getOrdering(),
|
||||||
'action_label' => $this->socialActionRender->renderString($action, []),
|
'action_label' => $this->socialActionRender->renderString($action, []),
|
||||||
'action_ordering' => $action->getOrdering(),
|
'action_ordering' => $action->getOrdering(),
|
||||||
'goal_label' => null !== $goal ? $this->stringHelper->localize($goal->getTitle()) : null,
|
'goal_label' => null !== $goal ? $this->stringHelper->localize($goal->getTitle()) : null,
|
||||||
|
@@ -44,6 +44,7 @@ readonly class SocialIssueCSVExportService
|
|||||||
'Id',
|
'Id',
|
||||||
'Label',
|
'Label',
|
||||||
'Social issue',
|
'Social issue',
|
||||||
|
'export.social_action_list.desactivation_date',
|
||||||
'socialIssue.isParent?',
|
'socialIssue.isParent?',
|
||||||
'socialIssue.Parent id',
|
'socialIssue.Parent id',
|
||||||
]
|
]
|
||||||
@@ -66,6 +67,7 @@ readonly class SocialIssueCSVExportService
|
|||||||
'id' => $issue->getId(),
|
'id' => $issue->getId(),
|
||||||
'label' => $this->stringHelper->localize($issue->getTitle()),
|
'label' => $this->stringHelper->localize($issue->getTitle()),
|
||||||
'title' => $this->socialIssueRender->renderString($issue, []),
|
'title' => $this->socialIssueRender->renderString($issue, []),
|
||||||
|
'export.social_action_list.desactivation_date' => $issue->getDesactivationDate()?->format('Y-m-d'),
|
||||||
'isParent' => $issue->hasChildren() ? 'X' : '',
|
'isParent' => $issue->hasChildren() ? 'X' : '',
|
||||||
'parent_id' => null !== $issue->getParent() ? $issue->getParent()->getId() : '',
|
'parent_id' => null !== $issue->getParent() ? $issue->getParent()->getId() : '',
|
||||||
];
|
];
|
||||||
|
@@ -52,6 +52,7 @@ class SocialActionCsvExporterTest extends TestCase
|
|||||||
// Création d'une instance réelle de SocialAction sans objectifs ni résultats
|
// Création d'une instance réelle de SocialAction sans objectifs ni résultats
|
||||||
$actionWithoutGoalsOrResults = new SocialAction();
|
$actionWithoutGoalsOrResults = new SocialAction();
|
||||||
$actionWithoutGoalsOrResults->setIssue($socialIssue);
|
$actionWithoutGoalsOrResults->setIssue($socialIssue);
|
||||||
|
$actionWithoutGoalsOrResults->setDesactivationDate(new \DateTime('2025-05-21'));
|
||||||
$actionWithoutGoalsOrResults->setTitle(['fr' => 'Action without goals or results']);
|
$actionWithoutGoalsOrResults->setTitle(['fr' => 'Action without goals or results']);
|
||||||
|
|
||||||
// Création d'une instance réelle de SocialAction avec des objectifs et des résultats
|
// Création d'une instance réelle de SocialAction avec des objectifs et des résultats
|
||||||
@@ -61,6 +62,7 @@ class SocialActionCsvExporterTest extends TestCase
|
|||||||
|
|
||||||
$actionWithGoalsAndResults = new SocialAction();
|
$actionWithGoalsAndResults = new SocialAction();
|
||||||
$actionWithGoalsAndResults->setIssue($socialIssue);
|
$actionWithGoalsAndResults->setIssue($socialIssue);
|
||||||
|
$actionWithGoalsAndResults->setDesactivationDate(new \DateTime('2025-05-21'));
|
||||||
$actionWithGoalsAndResults->setTitle(['fr' => 'Action with goals and results']);
|
$actionWithGoalsAndResults->setTitle(['fr' => 'Action with goals and results']);
|
||||||
$actionWithGoalsAndResults->addGoal($goalWithResult);
|
$actionWithGoalsAndResults->addGoal($goalWithResult);
|
||||||
|
|
||||||
@@ -68,6 +70,7 @@ class SocialActionCsvExporterTest extends TestCase
|
|||||||
$goalWithoutResult = new Goal();
|
$goalWithoutResult = new Goal();
|
||||||
$actionWithGoalsNoResults = new SocialAction();
|
$actionWithGoalsNoResults = new SocialAction();
|
||||||
$actionWithGoalsNoResults->setIssue($socialIssue);
|
$actionWithGoalsNoResults->setIssue($socialIssue);
|
||||||
|
$actionWithGoalsNoResults->setDesactivationDate(new \DateTime('2025-05-21'));
|
||||||
$actionWithGoalsNoResults->setTitle(['fr' => 'Action with goals and no results']);
|
$actionWithGoalsNoResults->setTitle(['fr' => 'Action with goals and no results']);
|
||||||
$actionWithGoalsNoResults->addGoal($goalWithoutResult);
|
$actionWithGoalsNoResults->addGoal($goalWithoutResult);
|
||||||
|
|
||||||
@@ -76,6 +79,7 @@ class SocialActionCsvExporterTest extends TestCase
|
|||||||
$resultWithNoAction->setTitle(['fr' => 'Result without objectives']);
|
$resultWithNoAction->setTitle(['fr' => 'Result without objectives']);
|
||||||
$actionWithResultsNoGoals = new SocialAction();
|
$actionWithResultsNoGoals = new SocialAction();
|
||||||
$actionWithResultsNoGoals->setIssue($socialIssue);
|
$actionWithResultsNoGoals->setIssue($socialIssue);
|
||||||
|
$actionWithResultsNoGoals->setDesactivationDate(new \DateTime('2025-05-21'));
|
||||||
$actionWithResultsNoGoals->setTitle(['fr' => 'Action with results and no goals']);
|
$actionWithResultsNoGoals->setTitle(['fr' => 'Action with results and no goals']);
|
||||||
$actionWithResultsNoGoals->addResult($resultWithNoAction);
|
$actionWithResultsNoGoals->addResult($resultWithNoAction);
|
||||||
|
|
||||||
@@ -91,11 +95,11 @@ class SocialActionCsvExporterTest extends TestCase
|
|||||||
$this->assertStringContainsString('Action with results and no goals', $content);
|
$this->assertStringContainsString('Action with results and no goals', $content);
|
||||||
|
|
||||||
self::assertEquals(<<<'CSV'
|
self::assertEquals(<<<'CSV'
|
||||||
export.social_action_list.action_id,export.social_action_list.social_issue_id,export.social_action_list.problematique_label,export.social_action_list.social_issue_ordering,export.social_action_list.action_label,export.social_action_list.action_ordering,export.social_action_list.goal_label,export.social_action_list.goal_id,export.social_action_list.goal_result_label,export.social_action_list.goal_result_id,export.social_action_list.result_without_goal_label,export.social_action_list.result_without_goal_id,export.social_action_list.evaluation_title,export.social_action_list.evaluation_id,export.social_action_list.evaluation_url,export.social_action_list.evaluation_delay_month,export.social_action_list.evaluation_delay_week,export.social_action_list.evaluation_delay_day
|
export.social_action_list.action_id,export.social_action_list.social_issue_id,export.social_action_list.problematique_label,export.social_action_list.desactivation_date,export.social_action_list.social_issue_ordering,export.social_action_list.action_label,export.social_action_list.action_ordering,export.social_action_list.goal_label,export.social_action_list.goal_id,export.social_action_list.goal_result_label,export.social_action_list.goal_result_id,export.social_action_list.result_without_goal_label,export.social_action_list.result_without_goal_id,export.social_action_list.evaluation_title,export.social_action_list.evaluation_id,export.social_action_list.evaluation_url,export.social_action_list.evaluation_delay_month,export.social_action_list.evaluation_delay_week,export.social_action_list.evaluation_delay_day
|
||||||
,,"Issue Title",0,"Action with goals and results",0,"not found",,"not found",,,,,,,,,
|
,,"Issue Title",2025-05-21,0,"Action with goals and results",0,"not found",,"not found",,,,,,,,,
|
||||||
,,"Issue Title",0,"Action without goals or results",0,,,,,,,,,,,,
|
,,"Issue Title",2025-05-21,0,"Action without goals or results",0,,,,,,,,,,,,
|
||||||
,,"Issue Title",0,"Action with goals and no results",0,"not found",,,,,,,,,,,
|
,,"Issue Title",2025-05-21,0,"Action with goals and no results",0,"not found",,,,,,,,,,,
|
||||||
,,"Issue Title",0,"Action with results and no goals",0,,,,,"Result without objectives",,,,,,,
|
,,"Issue Title",2025-05-21,0,"Action with results and no goals",0,,,,,"Result without objectives",,,,,,,
|
||||||
|
|
||||||
CSV, $content);
|
CSV, $content);
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,43 @@
|
|||||||
|
<?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\Migrations\Person;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20250514115009 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Allow more characters for maritalstatus id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
ALTER TABLE chill_person_marital_status ALTER id TYPE VARCHAR(15)
|
||||||
|
SQL);
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
ALTER TABLE chill_person_person ALTER maritalstatus_id TYPE VARCHAR(15)
|
||||||
|
SQL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
ALTER TABLE chill_person_person ALTER maritalStatus_id TYPE VARCHAR(7)
|
||||||
|
SQL);
|
||||||
|
$this->addSql(<<<'SQL'
|
||||||
|
ALTER TABLE chill_person_marital_status ALTER id TYPE VARCHAR(7)
|
||||||
|
SQL);
|
||||||
|
}
|
||||||
|
}
|
@@ -804,7 +804,7 @@ person_admin:
|
|||||||
|
|
||||||
# specific to accompanying period
|
# specific to accompanying period
|
||||||
accompanying_period:
|
accompanying_period:
|
||||||
deleted: Parcours d'accompagnment supprimé
|
deleted: Parcours d'accompagnement supprimé
|
||||||
dates: Période
|
dates: Période
|
||||||
dates_from_%opening_date%: Ouvert depuis le %opening_date%
|
dates_from_%opening_date%: Ouvert depuis le %opening_date%
|
||||||
dates_from_%opening_date%_to_%closing_date%: Ouvert du %opening_date% au %closing_date%
|
dates_from_%opening_date%_to_%closing_date%: Ouvert du %opening_date% au %closing_date%
|
||||||
@@ -843,6 +843,7 @@ accompanying_course:
|
|||||||
administrative_location: Localisation administrative
|
administrative_location: Localisation administrative
|
||||||
comment is pinned: Le commentaire est épinglé
|
comment is pinned: Le commentaire est épinglé
|
||||||
comment is unpinned: Le commentaire est désépinglé
|
comment is unpinned: Le commentaire est désépinglé
|
||||||
|
|
||||||
show: Montrer
|
show: Montrer
|
||||||
hide: Masquer
|
hide: Masquer
|
||||||
closed periods: parcours clôturés
|
closed periods: parcours clôturés
|
||||||
@@ -851,6 +852,7 @@ Social work configuration: Gestion des actions d'accompagnement social
|
|||||||
|
|
||||||
# Accompanying Course comments
|
# Accompanying Course comments
|
||||||
Accompanying Course Comment: Commentaire
|
Accompanying Course Comment: Commentaire
|
||||||
|
Accompanying Course Comments: Commentaires
|
||||||
Accompanying Course Comment list: Commentaires du parcours
|
Accompanying Course Comment list: Commentaires du parcours
|
||||||
pinned: épinglé
|
pinned: épinglé
|
||||||
Pin comment: Épingler
|
Pin comment: Épingler
|
||||||
@@ -919,6 +921,7 @@ accompanying_course_work:
|
|||||||
date_filter: Filtrer par date
|
date_filter: Filtrer par date
|
||||||
types_filter: Filtrer par type d'action
|
types_filter: Filtrer par type d'action
|
||||||
user_filter: Filtrer par intervenant
|
user_filter: Filtrer par intervenant
|
||||||
|
On-going works over total: Actions en cours / Actions du parcours
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@@ -624,7 +624,7 @@ final class SingleTaskController extends AbstractController
|
|||||||
->addCheckbox('status', $statuses, $statuses, $statusTrans);
|
->addCheckbox('status', $statuses, $statuses, $statusTrans);
|
||||||
|
|
||||||
$states = $this->singleTaskStateRepository->findAllExistingStates();
|
$states = $this->singleTaskStateRepository->findAllExistingStates();
|
||||||
$checked = array_values(array_filter($states, fn (string $state) => !in_array($state, ['closed', 'canceled', 'validated'], true)));
|
$checked = array_values(array_filter($states, fn (string $state) => !in_array($state, ['in_progress', 'closed', 'canceled', 'validated'], true)));
|
||||||
|
|
||||||
if ([] !== $states) {
|
if ([] !== $states) {
|
||||||
$filterBuilder
|
$filterBuilder
|
||||||
|
@@ -65,6 +65,7 @@ class ThirdpartyCSVExportController extends AbstractController
|
|||||||
'Name',
|
'Name',
|
||||||
'Profession',
|
'Profession',
|
||||||
'Telephone',
|
'Telephone',
|
||||||
|
'Telephone2',
|
||||||
'Email',
|
'Email',
|
||||||
'Address',
|
'Address',
|
||||||
'Comment',
|
'Comment',
|
||||||
@@ -76,6 +77,7 @@ class ThirdpartyCSVExportController extends AbstractController
|
|||||||
'Contact name',
|
'Contact name',
|
||||||
'Contact firstname',
|
'Contact firstname',
|
||||||
'Contact phone',
|
'Contact phone',
|
||||||
|
'Contact phone2',
|
||||||
'Contact email',
|
'Contact email',
|
||||||
'Contact address',
|
'Contact address',
|
||||||
'Contact profession',
|
'Contact profession',
|
||||||
|
@@ -209,6 +209,11 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface, \Strin
|
|||||||
#[PhonenumberConstraint(type: 'any')]
|
#[PhonenumberConstraint(type: 'any')]
|
||||||
private ?PhoneNumber $telephone = null;
|
private ?PhoneNumber $telephone = null;
|
||||||
|
|
||||||
|
#[Groups(['read', 'write', 'docgen:read', 'docgen:read:3party:parent'])]
|
||||||
|
#[ORM\Column(name: 'telephone2', type: 'phone_number', nullable: true)]
|
||||||
|
#[PhonenumberConstraint(type: 'any')]
|
||||||
|
private ?PhoneNumber $telephone2 = null;
|
||||||
|
|
||||||
#[ORM\Column(name: 'types', type: \Doctrine\DBAL\Types\Types::JSON, nullable: true)]
|
#[ORM\Column(name: 'types', type: \Doctrine\DBAL\Types\Types::JSON, nullable: true)]
|
||||||
private ?array $thirdPartyTypes = [];
|
private ?array $thirdPartyTypes = [];
|
||||||
|
|
||||||
@@ -429,6 +434,11 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface, \Strin
|
|||||||
return $this->telephone;
|
return $this->telephone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getTelephone2(): ?PhoneNumber
|
||||||
|
{
|
||||||
|
return $this->telephone2;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get type.
|
* Get type.
|
||||||
*/
|
*/
|
||||||
@@ -712,6 +722,13 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface, \Strin
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setTelephone2(?PhoneNumber $telephone2 = null): self
|
||||||
|
{
|
||||||
|
$this->telephone2 = $telephone2;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set type.
|
* Set type.
|
||||||
*
|
*
|
||||||
|
@@ -59,6 +59,10 @@ class ThirdPartyType extends AbstractType
|
|||||||
'label' => 'Phonenumber',
|
'label' => 'Phonenumber',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
])
|
])
|
||||||
|
->add('telephone2', ChillPhoneNumberType::class, [
|
||||||
|
'label' => 'telephone2',
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
->add('email', EmailType::class, [
|
->add('email', EmailType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
])
|
])
|
||||||
|
@@ -42,6 +42,7 @@ class ThirdPartyRepository implements ObjectRepository
|
|||||||
parent.name AS name,
|
parent.name AS name,
|
||||||
parent.profession AS profession,
|
parent.profession AS profession,
|
||||||
parent.telephone AS telephone,
|
parent.telephone AS telephone,
|
||||||
|
parent.telephone2 AS telephone2,
|
||||||
parent.email AS email,
|
parent.email AS email,
|
||||||
CONCAT_WS(' ', parent_address.street, parent_address.streetnumber, parent_postal.code, parent_postal.label) AS address,
|
CONCAT_WS(' ', parent_address.street, parent_address.streetnumber, parent_postal.code, parent_postal.label) AS address,
|
||||||
parent.comment AS comment,
|
parent.comment AS comment,
|
||||||
@@ -55,6 +56,7 @@ class ThirdPartyRepository implements ObjectRepository
|
|||||||
contact.name AS contact_name,
|
contact.name AS contact_name,
|
||||||
contact.firstname AS contact_firstname,
|
contact.firstname AS contact_firstname,
|
||||||
contact.telephone AS contact_phone,
|
contact.telephone AS contact_phone,
|
||||||
|
contact.telephone2 AS contact_phone2,
|
||||||
contact.email AS contact_email,
|
contact.email AS contact_email,
|
||||||
contact.profession AS contact_profession,
|
contact.profession AS contact_profession,
|
||||||
CONCAT_WS(' ', contact_address.street, contact_address.streetnumber, contact_postal.code, contact_postal.label) AS contact_address
|
CONCAT_WS(' ', contact_address.street, contact_address.streetnumber, contact_postal.code, contact_postal.label) AS contact_address
|
||||||
|
@@ -91,6 +91,18 @@
|
|||||||
}}</a
|
}}</a
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
|
<li v-if="thirdparty.telephone2">
|
||||||
|
<i class="fa fa-li fa-mobile" />
|
||||||
|
<a
|
||||||
|
:href="
|
||||||
|
'tel: ' +
|
||||||
|
thirdparty.telephone2
|
||||||
|
"
|
||||||
|
>{{
|
||||||
|
thirdparty.telephone2
|
||||||
|
}}</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
<li v-if="thirdparty.email">
|
<li v-if="thirdparty.email">
|
||||||
<i
|
<i
|
||||||
class="fa fa-li fa-envelope-o"
|
class="fa fa-li fa-envelope-o"
|
||||||
@@ -121,6 +133,12 @@
|
|||||||
thirdparty.telephone
|
thirdparty.telephone
|
||||||
}}</a>
|
}}</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li v-if="thirdparty.telephone2">
|
||||||
|
<i class="fa fa-li fa-mobile" />
|
||||||
|
<a :href="'tel: ' + thirdparty.telephone2"
|
||||||
|
>{{ thirdparty.telephone2 }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li v-if="thirdparty.email">
|
<li v-if="thirdparty.email">
|
||||||
<i class="fa fa-li fa-envelope-o" />
|
<i class="fa fa-li fa-envelope-o" />
|
||||||
<a :href="'mailto: ' + thirdparty.email">{{
|
<a :href="'mailto: ' + thirdparty.email">{{
|
||||||
|
@@ -223,6 +223,19 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-text" id="phonenumber2"
|
||||||
|
><i class="fa fa-fw fa-phone"
|
||||||
|
/></span>
|
||||||
|
<input
|
||||||
|
class="form-control form-control-lg"
|
||||||
|
v-model="thirdparty.telephone2"
|
||||||
|
:placeholder="$t('thirdparty.phonenumber2')"
|
||||||
|
:aria-label="$t('thirdparty.phonenumber2')"
|
||||||
|
aria-describedby="phonenumber2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="parent">
|
<div v-if="parent">
|
||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
<span class="input-group-text" id="comment"
|
<span class="input-group-text" id="comment"
|
||||||
@@ -263,6 +276,7 @@ export default {
|
|||||||
firstname: "",
|
firstname: "",
|
||||||
name: "",
|
name: "",
|
||||||
telephone: "",
|
telephone: "",
|
||||||
|
telephone2: "",
|
||||||
civility: null,
|
civility: null,
|
||||||
profession: "",
|
profession: "",
|
||||||
},
|
},
|
||||||
@@ -368,9 +382,11 @@ export default {
|
|||||||
addQueryItem(field, queryItem) {
|
addQueryItem(field, queryItem) {
|
||||||
switch (field) {
|
switch (field) {
|
||||||
case "name":
|
case "name":
|
||||||
this.thirdparty.name
|
if (this.thirdparty.name) {
|
||||||
? (this.thirdparty.name += ` ${queryItem}`)
|
this.thirdparty.name += ` ${queryItem}`;
|
||||||
: (this.thirdparty.name = queryItem);
|
} else {
|
||||||
|
this.thirdparty.name = queryItem;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "firstName":
|
case "firstName":
|
||||||
this.thirdparty.firstname = queryItem;
|
this.thirdparty.firstname = queryItem;
|
||||||
|
@@ -6,6 +6,7 @@ const thirdpartyMessages = {
|
|||||||
name: "Dénomination",
|
name: "Dénomination",
|
||||||
email: "Courriel",
|
email: "Courriel",
|
||||||
phonenumber: "Téléphone",
|
phonenumber: "Téléphone",
|
||||||
|
phonenumber2: "Autre numéro de téléphone",
|
||||||
comment: "Commentaire",
|
comment: "Commentaire",
|
||||||
profession: "Qualité",
|
profession: "Qualité",
|
||||||
civility: "Civilité",
|
civility: "Civilité",
|
||||||
|
@@ -115,6 +115,10 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<span class="chill-no-data-statement">{{ 'thirdparty.No_phonenumber'|trans }}</span>
|
<span class="chill-no-data-statement">{{ 'thirdparty.No_phonenumber'|trans }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if thirdparty.telephone2 is not null %}
|
||||||
|
{% if thirdparty.telephone is not null %}, {% endif %}
|
||||||
|
<a href="{{ 'tel:' ~ thirdparty.telephone2|phone_number_format('E164') }}">{{ thirdparty.telephone2|chill_format_phonenumber }}</a>
|
||||||
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
<li><i class="fa fa-li fa-envelope-o"></i>
|
<li><i class="fa fa-li fa-envelope-o"></i>
|
||||||
<a href="{{ 'mailto:' ~ thirdparty.email }}">
|
<a href="{{ 'mailto:' ~ thirdparty.email }}">
|
||||||
@@ -135,8 +139,14 @@
|
|||||||
}) }}
|
}) }}
|
||||||
</li>
|
</li>
|
||||||
<li><i class="fa fa-li fa-phone"></i>
|
<li><i class="fa fa-li fa-phone"></i>
|
||||||
{% if thirdparty.telephone %}
|
{% if thirdparty.telephone or thirdparty.telephone2 %}
|
||||||
<a href="{{ 'tel:' ~ thirdparty.telephone|phone_number_format('E164') }}">{{ thirdparty.telephone|chill_format_phonenumber }}</a>
|
{% if thirdparty.telephone is not null %}
|
||||||
|
<a href="{{ 'tel:' ~ thirdparty.telephone|phone_number_format('E164') }}">{{ thirdparty.telephone|chill_format_phonenumber }}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if thirdparty.telephone2 is not null %}
|
||||||
|
{% if thirdparty.telephone is not null %}, {% endif %}
|
||||||
|
<a href="{{ 'tel:' ~ thirdparty.telephone2|phone_number_format('E164') }}">{{ thirdparty.telephone2|chill_format_phonenumber }}</a>
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="chill-no-data-statement">{{ 'thirdparty.No_phonenumber'|trans }}</span>
|
<span class="chill-no-data-statement">{{ 'thirdparty.No_phonenumber'|trans }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@@ -22,6 +22,7 @@
|
|||||||
{{ form_row(form.typesAndCategories) }}
|
{{ form_row(form.typesAndCategories) }}
|
||||||
|
|
||||||
{{ form_row(form.telephone) }}
|
{{ form_row(form.telephone) }}
|
||||||
|
{{ form_row(form.telephone2) }}
|
||||||
{{ form_row(form.email) }}
|
{{ form_row(form.email) }}
|
||||||
|
|
||||||
{% if form.contactDataAnonymous is defined %}
|
{% if form.contactDataAnonymous is defined %}
|
||||||
|
@@ -24,17 +24,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="form-group col-md-5 mb-3">
|
<div class="form-group col-md-6 mb-3">
|
||||||
{{ form_widget(form.telephone) }}
|
{{ form_widget(form.telephone) }}
|
||||||
{{ form_errors(form.telephone) }}
|
{{ form_errors(form.telephone) }}
|
||||||
{{ form_label(form.telephone) }}
|
{{ form_label(form.telephone) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-md-5 mb-3">
|
<div class="form-group col-md-6 mb-3">
|
||||||
|
{{ form_widget(form.telephone2) }}
|
||||||
|
{{ form_errors(form.telephone2) }}
|
||||||
|
{{ form_label(form.telephone2) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="form-group col-md-6 mb-3">
|
||||||
{{ form_widget(form.email) }}
|
{{ form_widget(form.email) }}
|
||||||
{{ form_errors(form.email) }}
|
{{ form_errors(form.email) }}
|
||||||
{{ form_label(form.email) }}
|
{{ form_label(form.email) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-md-2 mb-3">
|
<div class="form-group col-md-6 mb-3">
|
||||||
{{ form_widget(form.contactDataAnonymous) }}
|
{{ form_widget(form.contactDataAnonymous) }}
|
||||||
{{ form_label(form.contactDataAnonymous) }}
|
{{ form_label(form.contactDataAnonymous) }}
|
||||||
{{ form_errors(form.contactDataAnonymous) }}
|
{{ form_errors(form.contactDataAnonymous) }}
|
||||||
|
@@ -76,6 +76,18 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
|
|
||||||
|
<dt>{{ 'Phonenumber2'|trans }}</dt>
|
||||||
|
<dd>
|
||||||
|
{% if thirdParty.telephone2 == null %}
|
||||||
|
<span class="chill-no-data-statement">{{ 'thirdparty.No_phonenumber'|trans }}</span>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ 'tel:' ~ thirdParty.telephone2|phone_number_format('E164') }}">
|
||||||
|
{{ thirdParty.telephone2|chill_format_phonenumber }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
|
|
||||||
<dt>{{ 'email'|trans }}<dt>
|
<dt>{{ 'email'|trans }}<dt>
|
||||||
<dd>
|
<dd>
|
||||||
{% if thirdParty.email == null %}
|
{% if thirdParty.email == null %}
|
||||||
|
@@ -55,6 +55,7 @@ class ThirdPartyNormalizer implements NormalizerAwareInterface, NormalizerInterf
|
|||||||
'profession' => $this->normalizer->normalize($thirdParty->getProfession(), $format, $context),
|
'profession' => $this->normalizer->normalize($thirdParty->getProfession(), $format, $context),
|
||||||
'address' => $this->normalizer->normalize($thirdParty->getAddress(), $format, ['address_rendering' => 'short']),
|
'address' => $this->normalizer->normalize($thirdParty->getAddress(), $format, ['address_rendering' => 'short']),
|
||||||
'telephone' => $this->normalizer->normalize($thirdParty->getTelephone(), $format, $context),
|
'telephone' => $this->normalizer->normalize($thirdParty->getTelephone(), $format, $context),
|
||||||
|
'telephone2' => $this->normalizer->normalize($thirdParty->getTelephone2(), $format, $context),
|
||||||
'email' => $thirdParty->getEmail(),
|
'email' => $thirdParty->getEmail(),
|
||||||
'isChild' => $thirdParty->isChild(),
|
'isChild' => $thirdParty->isChild(),
|
||||||
'parent' => $this->normalizer->normalize($thirdParty->getParent(), $format, $context),
|
'parent' => $this->normalizer->normalize($thirdParty->getParent(), $format, $context),
|
||||||
|
@@ -28,6 +28,8 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
telephone:
|
telephone:
|
||||||
type: string
|
type: string
|
||||||
|
telephone2:
|
||||||
|
type: string
|
||||||
address:
|
address:
|
||||||
$ref: "#/components/schemas/Address"
|
$ref: "#/components/schemas/Address"
|
||||||
Address:
|
Address:
|
||||||
|
@@ -0,0 +1,34 @@
|
|||||||
|
<?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\Migrations\ThirdParty;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20250325085950 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Add a second telephone number to ThirdParty';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_3party.third_party ADD telephone2 VARCHAR(35) DEFAULT NULL');
|
||||||
|
$this->addSql('COMMENT ON COLUMN chill_3party.third_party.telephone2 IS \'(DC2Type:phone_number)\'');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_3party.third_party DROP telephone2');
|
||||||
|
}
|
||||||
|
}
|
@@ -4,6 +4,7 @@ third parties: tiers
|
|||||||
firstname: Prénom
|
firstname: Prénom
|
||||||
name: Nom
|
name: Nom
|
||||||
telephone: Téléphone
|
telephone: Téléphone
|
||||||
|
telephone2: Autre numéro de téléphone
|
||||||
adress: Adresse
|
adress: Adresse
|
||||||
email: Courriel
|
email: Courriel
|
||||||
comment: Commentaire
|
comment: Commentaire
|
||||||
@@ -39,7 +40,7 @@ thirdparty.A contact: Une personne physique
|
|||||||
thirdparty.contact: Personne physique
|
thirdparty.contact: Personne physique
|
||||||
thirdparty.Contact of: Contact de
|
thirdparty.Contact of: Contact de
|
||||||
thirdparty.a_company_explanation: >-
|
thirdparty.a_company_explanation: >-
|
||||||
Les personnes morales peuvent compter un ou plusieurs contacts, interne à l'instution. Il est également possible de
|
Les personnes morales peuvent compter un ou plusieurs contacts, interne à l'institution. Il est également possible de
|
||||||
leur associer un acronyme, et le nom d'un service.
|
leur associer un acronyme, et le nom d'un service.
|
||||||
thirdparty.a_contact_explanation: >-
|
thirdparty.a_contact_explanation: >-
|
||||||
Les personnes physiques ne disposent pas d'acronyme, de service, ou de contacts sous-jacents. Il est possible de leur
|
Les personnes physiques ne disposent pas d'acronyme, de service, ou de contacts sous-jacents. Il est possible de leur
|
||||||
@@ -149,6 +150,8 @@ Contact id: Identifiant du contact
|
|||||||
Contact name: Nom du contact
|
Contact name: Nom du contact
|
||||||
Contact firstname: Prénom du contact
|
Contact firstname: Prénom du contact
|
||||||
Contact phone: Téléphone du contact
|
Contact phone: Téléphone du contact
|
||||||
|
Contact phone2: Autre téléphone du contact
|
||||||
|
Telephone2: Autre téléphone
|
||||||
Contact email: Courrier électronique du contact
|
Contact email: Courrier électronique du contact
|
||||||
Contact address: Adresse du contact
|
Contact address: Adresse du contact
|
||||||
Contact profession: Profession du contact
|
Contact profession: Profession du contact
|
||||||
|
Reference in New Issue
Block a user