diff --git a/src/app/backend/reseaux/page.tsx b/src/app/backend/reseaux/page.tsx index b85aa34..71dcd67 100644 --- a/src/app/backend/reseaux/page.tsx +++ b/src/app/backend/reseaux/page.tsx @@ -23,7 +23,14 @@ export const dynamic = "force-dynamic"; const HELP: Record< (typeof SOCIAL_NETWORKS)[number], - { portal: string; steps: string[]; caution?: string; tools?: { label: string; href: string }[] } + { + portal: string; + steps: string[]; + caution?: string; + tools?: { label: string; href: string }[]; + /** Les deux liens utiles au moment de renouveler un jeton. */ + renew: { note: string; links: { label: string; hint: string; href: string }[] }; + } > = { facebook: { portal: "https://developers.facebook.com/apps", @@ -32,6 +39,23 @@ const HELP: Record< "Ajoutez le produit « Connexion Facebook » puis collez l'URL de redirection ci-dessous dans « URI de redirection OAuth valides ».", "Laissez l'application en mode développement et ajoutez le compte de l'association comme administrateur : publier sur votre propre page ne demande alors aucune revue Meta.", ], + renew: { + note: + "Le bouton refait tout l'échange : jeton court, puis jeton de longue durée, puis jeton de page. " + + "Vous n'avez aucun jeton à copier à la main — les deux liens ci-dessous ne servent qu'à vérifier.", + links: [ + { + label: "Débogueur de jeton", + hint: "coller un jeton pour voir sa validité et sa date d'expiration", + href: "https://developers.facebook.com/tools/debug/accesstoken/", + }, + { + label: "Outil de jetons d'accès", + hint: "lister les jetons de vos pages et en générer un de longue durée", + href: "https://developers.facebook.com/tools/accesstoken/", + }, + ], + }, tools: [ { label: "Débogueur de jeton (vérifier un jeton et sa date d'expiration)", href: "https://developers.facebook.com/tools/debug/accesstoken/" }, { label: "Outil de jetons d'accès (voir les jetons de vos pages)", href: "https://developers.facebook.com/tools/accesstoken/" }, @@ -47,7 +71,24 @@ const HELP: Record< "Onglet Produits : demandez « Community Management API », indispensable pour publier au nom de la page.", ], caution: - "LinkedIn soumet cette demande à une revue (page vérifiée, nom légal, adresse, politique de confidentialité) et ses jetons expirent au bout de 60 jours : il faudra recliquer sur Reconnecter environ tous les deux mois.", + "LinkedIn soumet cette demande à une revue (page vérifiée, nom légal, adresse, politique de confidentialité) et ses jetons expirent au bout de 60 jours : il faudra recliquer sur « Renouveler le jeton » environ tous les deux mois.", + renew: { + note: + "Les jetons LinkedIn expirent au bout de 60 jours : le bouton relance l'autorisation et " + + "repart pour deux mois. Les deux liens ci-dessous permettent de contrôler l'échéance.", + links: [ + { + label: "Jetons de votre application", + hint: "voir la durée de validité restante des jetons émis", + href: "https://www.linkedin.com/developers/tools/oauth", + }, + { + label: "Documentation : durée de vie des jetons", + hint: "règles de rafraîchissement et conditions d'accès", + href: "https://learn.microsoft.com/linkedin/shared/authentication/programmatic-refresh-tokens", + }, + ], + }, tools: [ { label: "Jetons de votre application (durée de validité)", href: "https://www.linkedin.com/developers/tools/oauth" }, { label: "Documentation : durée de vie et rafraîchissement des jetons", href: "https://learn.microsoft.com/linkedin/shared/authentication/programmatic-refresh-tokens" }, @@ -164,6 +205,9 @@ export default async function ReseauxPage({ const candidates = targets.get(network) ?? []; const tokenHealth = health.get(network) ?? null; const broken = tokenHealth?.ok === false; + // Le bloc de renouvellement passe en ambre quand il y a urgence : + // jeton mort, expiré, ou sur le point de l'être. + const needsRenewal = broken || status === "expired" || status === "soon"; return (
@@ -201,14 +245,14 @@ export default async function ReseauxPage({ ✓ Jeton vérifié à l'instant auprès de {SOCIAL_LABELS[network]} : il fonctionne.{" "} )} - Pour changer de page, relancez une connexion. + Pour changer de page ou renouveler l'accès, utilisez le bouton ci-dessous. )} {broken && ( Le jeton {SOCIAL_LABELS[network]} ne fonctionne plus : les publications échoueront - tant que vous n'aurez pas cliqué sur Reconnecter. + tant que vous n'aurez pas cliqué sur « Renouveler le jeton ».
Réponse de la plateforme : {tokenHealth.reason.slice(0, 220)}
@@ -218,8 +262,8 @@ export default async function ReseauxPage({ {(status === "soon" || status === "expired") && isConnected && ( {status === "expired" - ? `Le jeton ${SOCIAL_LABELS[network]} a expiré : les publications échoueront tant que vous n'aurez pas reconnecté le compte.` - : `Le jeton ${SOCIAL_LABELS[network]} expire bientôt. Un clic sur Reconnecter suffit à le renouveler.`} + ? `Le jeton ${SOCIAL_LABELS[network]} a expiré : les publications échoueront tant que vous ne l'aurez pas renouvelé.` + : `Le jeton ${SOCIAL_LABELS[network]} expire bientôt. Un clic sur « Renouveler le jeton » suffit.`} )} @@ -272,24 +316,91 @@ export default async function ReseauxPage({ -
- - {isConnected ? "Reconnecter" : "Connecter"} - +
+ Renouveler le jeton +
+
+ {help.renew.note} +
+ + Renouveler le jeton {SOCIAL_LABELS[network]} + +
+ {help.renew.links.map((link) => ( + + {link.label} ↗ + + {link.hint} + + + ))} +
+
+ )} + +
+ {/* Une fois connecté, l'action vit dans le bloc de renouvellement + ci-dessus : deux boutons identiques côte à côte n'aidaient personne. */} + {!isConnected && ( + + Connecter + + )} {isConnected && (