mirror of
https://github.com/siop-spelev/siop2.git
synced 2026-08-08 12:41:54 +00:00
feat(r6): R6.4 — Pilotage sur mobile (Statistiques, Personnes)
EXPO_PUBLIC_WEB_URL/WEB_URL pour le lien d'activation (pointe la page web /activation?token=…, aucun équivalent mobile). api/pilotage.ts (useAnalyticsSummary, useUsers, useRoles, useInviteUser). Écran Statistiques (maquette écran 7) : période 3/6/12 mois, coût du mois, taux préventif, OT clôturés, pannes par organe, top équipements — cartes plutôt que graphes denses (D4). Écran Personnes & équipes : liste + statut, Inviter (nom/e-mail/rôle), lien d'activation en texte sélectionnable (Text selectable, RN natif) — expo-clipboard est une dépendance native absente, différée comme expo-sharing en R6.3 plutôt qu'ajoutée à la légère. Taux horaire/rôles/ équipes restent gérés au web (D4). Assistant reste "à venir" dans le Menu : un chat sourcé est un nouveau patron d'écran jamais maquetté sur mobile, contrairement aux autres familles qui réutilisaient des patrons déjà validés — mérite son propre tour de design-first plutôt qu'être exécuté par réflexe en fin de release. R6 quasi close (Exploitation/Parc/Ressources/Pilotage livrés pour tous les rôles, hors Assistant) — reste la confirmation du référent sur iPhone (R6.1 + correctif déconnexion) avant clôture réelle. Typecheck propre, 17 tests Jest, lint 5/5 paquets. Contrat non touché. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,11 @@ import { lireJeton } from './jeton';
|
||||
* EXPO_PUBLIC_API_URL pointe l'API (IP LAN pour Expo Go sur téléphone). */
|
||||
export const API_URL = process.env.EXPO_PUBLIC_API_URL ?? 'http://localhost:3000';
|
||||
|
||||
/** Origine du web (R6.4 — lien d'activation « Personnes », même page
|
||||
* `/activation?token=…` que le web, il n'existe pas d'équivalent mobile).
|
||||
* À définir par environnement comme EXPO_PUBLIC_API_URL. */
|
||||
export const WEB_URL = process.env.EXPO_PUBLIC_WEB_URL ?? 'http://localhost:5173';
|
||||
|
||||
export const api = createClient<paths>({ baseUrl: API_URL });
|
||||
|
||||
api.use({
|
||||
|
||||
39
apps/mobile/src/api/pilotage.ts
Normal file
39
apps/mobile/src/api/pilotage.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import type { InvitationCreate } from '@siop/shared';
|
||||
import { api, unwrap } from './client';
|
||||
|
||||
/** Hooks R6.4 — Pilotage (Statistiques, Personnes & équipes) : mêmes
|
||||
* opérations que le web (gestion.ts/referentiel.ts), lecture + une action
|
||||
* courante (inviter) sur mobile — pas la gestion complète des rôles/
|
||||
* équipes/taux horaires, réservée au web (D4). */
|
||||
|
||||
export function useAnalyticsSummary(months: 3 | 6 | 12 = 12) {
|
||||
return useQuery({
|
||||
queryKey: ['analytics', months],
|
||||
queryFn: async () =>
|
||||
unwrap(await api.GET('/analytics/summary', { params: { query: { months: String(months) } } })),
|
||||
});
|
||||
}
|
||||
|
||||
export function useUsers() {
|
||||
return useQuery({
|
||||
queryKey: ['users'],
|
||||
queryFn: async () => (await unwrap(await api.GET('/users'))).users,
|
||||
});
|
||||
}
|
||||
|
||||
export function useRoles() {
|
||||
return useQuery({
|
||||
queryKey: ['roles'],
|
||||
queryFn: async () => (await unwrap(await api.GET('/roles'))).roles,
|
||||
});
|
||||
}
|
||||
|
||||
export function useInviteUser() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async (body: InvitationCreate) =>
|
||||
unwrap(await api.POST('/users/invitations', { body })),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] }),
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user