From f56d84e76b1ded6d2c3612f7530dbd7cee324217 Mon Sep 17 00:00:00 2001
From: Yvv
Date: Sat, 25 Apr 2026 20:48:27 +0200
Subject: [PATCH] =?UTF-8?q?Mandats=20:=20origin=E2=86=92FK=20identit=C3=A9?=
=?UTF-8?q?=20+=20nomination=20auto=20+=20boutons=20+=20tests=20int=C3=A9g?=
=?UTF-8?q?ration?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- origin TEXT → origin_id UUID FK duniter_identities (migration e3f4a5b6c7d8)
- GET /auth/identities?q= : recherche d'identités par nom/adresse
- MandateCreate.nomination_mode : auto (auto-assign auteur), collective, postpone
- Wizard new.vue : champ origine = picker identité, checkbox "Démarrer maintenant"
- [id].vue : modal "Assigner" = search-picker (résout UUID vs adresse SS58), affiche
origin_display_name + mandatee_display_name, inputs natifs (/
- Origine : {{ origin }}
+ Proposé par : {{ originQuery }}
{{ description }}
@@ -732,6 +792,18 @@ function selectNomination(c: NominationCase) {
+
+
+
+
+ Le mandat passera en phase de nomination dès la création.
+ Le mandat restera en brouillon — à démarrer manuellement depuis la fiche.
+
+
+
{{ submitError }}
@@ -1173,6 +1245,32 @@ function selectNomination(c: NominationCase) {
.mwiz__error { color: var(--mood-danger, #e53e3e); font-size: 0.875rem; padding: 0.5rem 0; }
+/* Start option */
+.mwiz__start-option {
+ background: var(--mood-surface);
+ border-radius: 16px;
+ padding: 1.125rem 1.25rem;
+ margin-bottom: 1rem;
+}
+.mwiz__start-label {
+ display: flex;
+ align-items: center;
+ gap: 0.625rem;
+ font-weight: 600;
+ font-size: 0.9375rem;
+ color: var(--mood-text);
+ cursor: pointer;
+}
+.mwiz__checkbox {
+ width: 1.125rem;
+ height: 1.125rem;
+ accent-color: var(--mood-accent);
+ cursor: pointer;
+ flex-shrink: 0;
+}
+.mwiz__start-hint { font-size: 0.8125rem; color: var(--mood-muted); margin-top: 0.375rem; padding-left: 1.75rem; }
+.mwiz__hint { font-size: 0.8125rem; margin-top: 0.25rem; }
+
/* Transitions */
.slide-fade-enter-active, .slide-fade-leave-active { transition: all 0.2s ease; }
.slide-fade-enter-from { opacity: 0; transform: translateX(20px); }
diff --git a/frontend/app/stores/mandates.ts b/frontend/app/stores/mandates.ts
index 99ba9d1..9749cc0 100644
--- a/frontend/app/stores/mandates.ts
+++ b/frontend/app/stores/mandates.ts
@@ -1,9 +1,3 @@
-/**
- * Mandates store: governance mandates and their lifecycle steps.
- *
- * Maps to the backend /api/v1/mandates endpoints.
- */
-
export interface MandateStep {
id: string
mandate_id: string
@@ -20,11 +14,13 @@ export interface MandateStep {
export interface Mandate {
id: string
title: string
- origin: string | null
+ origin_id: string | null
+ origin_display_name: string | null
description: string | null
mandate_type: string
status: string
mandatee_id: string | null
+ mandatee_display_name: string | null
decision_id: string | null
starts_at: string | null
ends_at: string | null
@@ -35,9 +31,10 @@ export interface Mandate {
export interface MandateCreate {
title: string
- origin?: string | null
+ origin_id?: string | null
description?: string | null
mandate_type: string
+ nomination_mode?: string
decision_id?: string | null
starts_at?: string | null
ends_at?: string | null
@@ -45,6 +42,7 @@ export interface MandateCreate {
export interface MandateUpdate {
title?: string
+ origin_id?: string | null
description?: string | null
mandate_type?: string
starts_at?: string | null
@@ -52,6 +50,7 @@ export interface MandateUpdate {
}
export interface MandateStepCreate {
+ step_order: number
step_type: string
title?: string | null
description?: string | null
@@ -73,31 +72,20 @@ export const useMandatesStore = defineStore('mandates', {
}),
getters: {
- byStatus: (state) => {
- return (status: string) => state.list.filter(m => m.status === status)
- },
- activeMandates: (state): Mandate[] => {
- return state.list.filter(m => m.status === 'active')
- },
- completedMandates: (state): Mandate[] => {
- return state.list.filter(m => m.status === 'completed')
- },
+ byStatus: (state) => (status: string) => state.list.filter(m => m.status === status),
+ activeMandates: (state): Mandate[] => state.list.filter(m => m.status === 'active'),
+ completedMandates: (state): Mandate[] => state.list.filter(m => m.status === 'completed'),
},
actions: {
- /**
- * Fetch all mandates with optional filters.
- */
async fetchAll(params?: { mandate_type?: string; status?: string }) {
this.loading = true
this.error = null
-
try {
const { $api } = useApi()
const query: Record = {}
if (params?.mandate_type) query.mandate_type = params.mandate_type
if (params?.status) query.status = params.status
-
this.list = await $api('/mandates/', { query })
} catch (err: any) {
this.error = err?.data?.detail || err?.message || 'Erreur lors du chargement des mandats'
@@ -106,13 +94,9 @@ export const useMandatesStore = defineStore('mandates', {
}
},
- /**
- * Fetch a single mandate by ID with all its steps.
- */
async fetchById(id: string) {
this.loading = true
this.error = null
-
try {
const { $api } = useApi()
this.current = await $api(`/mandates/${id}`)
@@ -123,19 +107,12 @@ export const useMandatesStore = defineStore('mandates', {
}
},
- /**
- * Create a new mandate.
- */
async create(payload: MandateCreate) {
this.loading = true
this.error = null
-
try {
const { $api } = useApi()
- const mandate = await $api('/mandates/', {
- method: 'POST',
- body: payload,
- })
+ const mandate = await $api('/mandates/', { method: 'POST', body: payload })
this.list.unshift(mandate)
return mandate
} catch (err: any) {
@@ -146,18 +123,11 @@ export const useMandatesStore = defineStore('mandates', {
}
},
- /**
- * Update an existing mandate.
- */
async update(id: string, data: MandateUpdate) {
this.error = null
-
try {
const { $api } = useApi()
- const updated = await $api(`/mandates/${id}`, {
- method: 'PUT',
- body: data,
- })
+ const updated = await $api(`/mandates/${id}`, { method: 'PUT', body: data })
if (this.current?.id === id) this.current = updated
const idx = this.list.findIndex(m => m.id === id)
if (idx >= 0) this.list[idx] = updated
@@ -168,12 +138,8 @@ export const useMandatesStore = defineStore('mandates', {
}
},
- /**
- * Delete a mandate.
- */
async delete(id: string) {
this.error = null
-
try {
const { $api } = useApi()
await $api(`/mandates/${id}`, { method: 'DELETE' })
@@ -185,17 +151,11 @@ export const useMandatesStore = defineStore('mandates', {
}
},
- /**
- * Advance the mandate to the next step in its workflow.
- */
async advance(id: string) {
this.error = null
-
try {
const { $api } = useApi()
- const updated = await $api(`/mandates/${id}/advance`, {
- method: 'POST',
- })
+ const updated = await $api(`/mandates/${id}/advance`, { method: 'POST' })
if (this.current?.id === id) this.current = updated
const idx = this.list.findIndex(m => m.id === id)
if (idx >= 0) this.list[idx] = updated
@@ -206,21 +166,12 @@ export const useMandatesStore = defineStore('mandates', {
}
},
- /**
- * Add a step to a mandate.
- */
async addStep(id: string, step: MandateStepCreate) {
this.error = null
-
try {
const { $api } = useApi()
- const newStep = await $api(`/mandates/${id}/steps`, {
- method: 'POST',
- body: step,
- })
- if (this.current?.id === id) {
- this.current.steps.push(newStep)
- }
+ const newStep = await $api(`/mandates/${id}/steps`, { method: 'POST', body: step })
+ if (this.current?.id === id) this.current.steps.push(newStep)
return newStep
} catch (err: any) {
this.error = err?.data?.detail || err?.message || 'Erreur lors de l\'ajout de l\'etape'
@@ -228,12 +179,8 @@ export const useMandatesStore = defineStore('mandates', {
}
},
- /**
- * Assign a mandatee to the mandate.
- */
async assignMandatee(id: string, mandateeId: string) {
this.error = null
-
try {
const { $api } = useApi()
const updated = await $api(`/mandates/${id}/assign`, {
@@ -250,17 +197,11 @@ export const useMandatesStore = defineStore('mandates', {
}
},
- /**
- * Revoke the mandate.
- */
async revoke(id: string) {
this.error = null
-
try {
const { $api } = useApi()
- const updated = await $api(`/mandates/${id}/revoke`, {
- method: 'POST',
- })
+ const updated = await $api(`/mandates/${id}/revoke`, { method: 'POST' })
if (this.current?.id === id) this.current = updated
const idx = this.list.findIndex(m => m.id === id)
if (idx >= 0) this.list[idx] = updated
@@ -271,9 +212,6 @@ export const useMandatesStore = defineStore('mandates', {
}
},
- /**
- * Clear the current mandate.
- */
clearCurrent() {
this.current = null
},