fix: resolve permission toggle persistence, nudge terminology, and bulk action bugs (Bugs #2-5)

- Fix togglePermission() to always include all permission keys with false defaults
- Add migration to backfill null/empty Manager permissions with config defaults
- Rename nudge UI text from "Relance" to "Notification"/"Notifier" across 8 files
- Fix select-all checkbox and show checkboxes on all declaration rows
- Remove en_attente_client status restriction from BulkNotificationController

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-27 13:40:30 +01:00
parent bc100491f1
commit 8f39bd9b73
17 changed files with 161 additions and 41 deletions

View File

@@ -74,8 +74,8 @@ function getDescription(notification: NotificationItem): string {
switch (type) {
case 'nudge':
return sender
? `Relance de ${sender} sur ${title}`
: `Relance sur ${title}`;
? `Notification de ${sender} sur ${title}`
: `Notification sur ${title}`;
case 'declaration_overdue':
return `Déclaration en retard : ${title}`;
case 'document_uploaded':

View File

@@ -48,7 +48,7 @@ function sendNudge() {
>
<div class="space-y-3">
<p class="text-sm">
Envoyer une relance à
Envoyer une notification à
<span class="font-medium">{{
assigneeName ?? 'Non assigné'
}}</span>
@@ -60,7 +60,7 @@ function sendNudge() {
@click="sendNudge"
>
<Send class="mr-2 h-4 w-4" />
Envoyer une relance
Envoyer une notification
</Button>
</div>
</PopoverContent>

View File

@@ -367,7 +367,7 @@ function navigateToDeclaration(declaration: DashboardDeclaration): void {
<Send
class="mr-2 h-4 w-4"
/>
Relancer
Notifier
</DropdownMenuItem>
<DropdownMenuItem
disabled

View File

@@ -59,32 +59,19 @@ watch(() => props.declarations.data, () => {
selectedIds.value = [];
});
const eligibleDeclarations = computed(() =>
props.declarations.data.filter(
(d) => d.status === 'en_attente_client',
),
);
const allEligibleSelected = computed(
const allSelected = computed(
() =>
eligibleDeclarations.value.length > 0 &&
eligibleDeclarations.value.every((d) =>
props.declarations.data.length > 0 &&
props.declarations.data.every((d) =>
selectedIds.value.includes(d.id),
),
);
function toggleSelectAll(checked: boolean | 'indeterminate') {
if (checked === true) {
const eligibleIds = eligibleDeclarations.value.map((d) => d.id);
const merged = new Set([...selectedIds.value, ...eligibleIds]);
selectedIds.value = [...merged];
selectedIds.value = props.declarations.data.map((d) => d.id);
} else {
const eligibleIds = new Set(
eligibleDeclarations.value.map((d) => d.id),
);
selectedIds.value = selectedIds.value.filter(
(id) => !eligibleIds.has(id),
);
selectedIds.value = [];
}
}
@@ -168,9 +155,9 @@ const columnCount = computed(() => (props.canBulkNotify ? 7 : 6));
class="h-10 w-10 px-4 text-center align-middle"
>
<Checkbox
:checked="allEligibleSelected"
:checked="allSelected"
:disabled="
eligibleDeclarations.length === 0
declarations.data.length === 0
"
@update:checked="toggleSelectAll"
/>
@@ -218,10 +205,6 @@ const columnCount = computed(() => (props.canBulkNotify ? 7 : 6));
class="px-4 py-3 text-center"
>
<Checkbox
v-if="
declaration.status ===
'en_attente_client'
"
:checked="
selectedIds.includes(
declaration.id,

View File

@@ -53,8 +53,8 @@ function getDescription(notification: AppNotification): string {
switch (type) {
case 'nudge':
return sender
? `Relance de ${sender} sur ${title}`
: `Relance sur ${title}`;
? `Notification de ${sender} sur ${title}`
: `Notification sur ${title}`;
case 'declaration_overdue':
return `Déclaration en retard : ${title}`;
case 'document_uploaded':

View File

@@ -139,7 +139,12 @@ function openPermissionsDialog(member: TeamMember) {
function togglePermission(key: string, value: boolean) {
if (!permissionsMember.value?.permissionsUrl) return;
// Ensure ALL permission keys are present, defaulting missing keys to false
const base = Object.fromEntries(
Object.keys(props.availablePermissions).map((k) => [k, false]),
);
const updatedPermissions = {
...base,
...permissionsMember.value.permissions,
[key]: value,
};

View File

@@ -1,9 +1,9 @@
<x-mail::message>
# Relance
# Notification
Bonjour,
**{{ $senderName }}** de **{{ $firmName }}** vous envoie une relance concernant la déclaration suivante :
**{{ $senderName }}** de **{{ $firmName }}** vous envoie une notification concernant la déclaration suivante :
- **Client :** {{ $clientName }}
- **Type :** {{ $declarationType }}