import { router } from 'expo-router';
import { useState } from 'react';
import { FlatList, Text, TextInput, View } from 'react-native';
import type { RequestSummary } from '@siop/shared';
import {
useApproveRequest,
useRejectRequest,
useRequests,
} from '@/api/exploitation';
import { useUsers } from '@/api/pilotage';
import { usePermissions } from '@/auth/use-permissions';
import { useTokens, type Tokens } from '@/theme/tokens';
import { BoutonTel, ChoixTel } from './ui';
/** Panneau Demandes — UN SEUL composant pour tous les rôles (maquette
* « mobile ouvert à tous les rôles », écran 5) : le Demandeur y crée et
* suit SES demandes ; Gestionnaire/Dispatcher/Administrateur y approuvent
* ou rejettent (motif obligatoire, comme au web) ; Vue seule consulte sans
* bouton. L'API renvoie déjà la liste correctement scopée (ADR-003) — ce
* composant affiche ce qu'on lui donne et ne propose que les actions
* permises par `can(...)`. */
export function PanneauDemandes() {
const t = useTokens();
const { can } = usePermissions();
const { data: requests } = useRequests();
const peutTraiter = can('REQUESTS', 'edit');
const peutCreer = can('REQUESTS', 'create');
const toutes = requests ?? [];
const aTraiter = toutes.filter((r) => r.status === 'RECEIVED').length;
return (
Demandes
{aTraiter} à traiter · {toutes.length} au total
{peutCreer ? (
router.push('/demandes/nouvelle')} />
) : null}
r.id}
contentContainerStyle={{ gap: 8, paddingBottom: 12 }}
ListEmptyComponent={
Aucune demande pour l'instant.
}
renderItem={({ item: r }) => }
/>
);
}
const STYLE_STATUT: Record [string, string]> = {
RECEIVED: (t) => [t.stAttente, t.stAttenteFond],
APPROVED: (t) => [t.stTermine, t.stTermineFond],
REJECTED: (t) => [t.stAnnule, t.stAnnuleFond],
};
const LABEL_STATUT: Record = {
RECEIVED: 'Reçue',
APPROVED: 'Approuvée',
REJECTED: 'Rejetée',
};
function CarteDemande({ demande: r, peutTraiter }: { demande: RequestSummary; peutTraiter: boolean }) {
const t = useTokens();
const { data: users } = useUsers();
const approbation = useApproveRequest();
const rejet = useRejectRequest();
// Un seul panneau ouvert à la fois : approbation (avec assignation — ce
// n'est pas au Gestionnaire d'agir comme un technicien, il délègue) ou
// rejet (motif obligatoire). null = fermé, les deux boutons côte à côte.
const [panneau, setPanneau] = useState<'approuver' | 'rejeter' | null>(null);
const [motif, setMotif] = useState('');
const [assigneId, setAssigneId] = useState(null);
const techniciens = (users ?? []).filter(
(u) => u.status === 'active' && u.role.name.startsWith('Technicien'),
);
const technicien = techniciens.find((tt) => tt.id === assigneId) ?? null;
const [enc, fond] = STYLE_STATUT[r.status](t);
const enCours = r.status === 'RECEIVED';
return (
{r.reference}
{LABEL_STATUT[r.status]}
{r.isPersonTrapped ? '⚠ ' : ''}
{r.description}
Asc. {r.assetReference} — {r.siteName} · {r.requesterLabel}
{r.rejectionReason ? (
Motif du rejet : {r.rejectionReason}
) : null}
{peutTraiter && enCours ? (
panneau === null ? (
setPanneau('approuver')} />
setPanneau('rejeter')} />
) : panneau === 'approuver' ? (
({ id: tt.id, label: tt.displayName }))}
surChoix={setAssigneId}
/>
{
setPanneau(null);
setAssigneId(null);
}}
/>
approbation.mutate(
{
id: r.id,
priority: r.isPersonTrapped ? 'PERSON_TRAPPED' : 'HIGH',
assigneeIds: assigneId ? [assigneId] : undefined,
},
{ onSuccess: () => setPanneau(null) },
)
}
/>
) : (
{
setPanneau(null);
setMotif('');
}}
/>
rejet.mutate(
{ id: r.id, reason: motif.trim() },
{ onSuccess: () => setPanneau(null) },
)
}
/>
)
) : null}
);
}