/* certificate.jsx — Cisco Arena certificate + feedback gate * Requires React 18 + Babel standalone. * For PNG download, load html2canvas before this file: * */ (function() { var useState = React.useState; var useMemo = React.useMemo; function clamp(n, min, max) { return Math.max(min, Math.min(max, n)); } function fmtNum(n) { return Number(n || 0).toLocaleString(); } function ordinal(n) { var v = Number(n || 0); if (!v) return '—'; var mod10 = v % 10; var mod100 = v % 100; if (mod10 === 1 && mod100 !== 11) return v + 'st'; if (mod10 === 2 && mod100 !== 12) return v + 'nd'; if (mod10 === 3 && mod100 !== 13) return v + 'rd'; return v + 'th'; } function rankLine(rank, totalPlayers, isWinner) { if (isWinner || Number(rank) === 1) return '🏆 1st Place — Champion'; return ordinal(rank) + ' of ' + Number(totalPlayers || 0) + ' racers'; } function podiumTone(rank, isWinner) { if (isWinner || Number(rank) === 1) return 'winner'; if (Number(rank) === 2) return 'silver'; if (Number(rank) === 3) return 'bronze'; return 'finisher'; } function certificateTitle(isWinner) { return isWinner ? 'Certificate of Champions' : 'Certificate of Completion'; } function shareCopy(props) { var pieces = [ 'I just completed the Cisco Arena ISE challenge', props.rank && props.totalPlayers ? '— finished ' + ordinal(props.rank) + ' of ' + props.totalPlayers : '', props.finalScore != null ? 'with ' + fmtNum(props.finalScore) + ' points!' : 'and unlocked my certificate!', '🏆 #CiscoArena #ISE' ].filter(Boolean); return pieces.join(' '); } var ArenaCertificate = React.forwardRef(function ArenaCertificate(props, ref) { var tone = podiumTone(props.rank, props.isWinner); var rootRef = props.certificateRef || ref; var accentStyle = { '--team-accent': props.teamColor || '#00BCEB' }; var champion = !!props.isWinner || Number(props.rank) === 1; return (
Cisco Arena
{props.eventName || 'Cisco Arena'}
{champion ? tc('🏆 CAMPEÓN') : tc('FINALISTA')}
{certificateTitle(champion)}

{props.playerName || 'Player Name'}

{tc('otorgado por completar')} {props.moduleName || 'Cisco Identity Services Engine'}
{tc('Equipo')} {props.teamName || tc('Equipo Cisco Arena')}
{tc('Posición final')} {rankLine(props.rank, props.totalPlayers, champion)}
{tc('Puntuación final')} {fmtNum(props.finalScore)} pts
{tc('Fecha')} {props.date || tc('Fecha del evento')}
Cisco Arena · {props.date || 'Event date'}
{champion ? '1' : ordinal(props.rank)}
of {props.totalPlayers || '—'} racers
); }); function CertificateActions(props) { var _status = useState('idle'), status = _status[0], setStatus = _status[1]; var shareText = useMemo(function() { return shareCopy(props); }, [props.playerName, props.rank, props.totalPlayers, props.finalScore, props.eventName]); var shareUrl = props.shareUrl || 'https://www.cisco.com'; function resolveNode() { if (!props.certificateRef) return null; return props.certificateRef.current || props.certificateRef; } function downloadPng() { var node = resolveNode(); if (!node) { setStatus('missing-ref'); return; } if (typeof window.html2canvas !== 'function') { setStatus('missing-lib'); return; } setStatus('rendering'); window.html2canvas(node, { backgroundColor: null, scale: Math.max(2, window.devicePixelRatio || 1), useCORS: true }).then(function(canvas) { var link = document.createElement('a'); var safeName = String(props.playerName || 'player').replace(/[^a-z0-9]+/gi, '-').replace(/^-|-$/g, '').toLowerCase() || 'player'; link.href = canvas.toDataURL('image/png'); link.download = safeName + '-cisco-arena-certificate.png'; link.click(); setStatus('downloaded'); }).catch(function() { setStatus('error'); }); } function shareToLinkedIn() { window.open('https://www.linkedin.com/sharing/share-offsite/?url=' + encodeURIComponent(shareUrl), '_blank', 'noopener,noreferrer'); } function copyShareText() { navigator.clipboard.writeText(shareText).then(function() { setStatus('copied'); }).catch(function() { setStatus('copy-error'); }); } return (
{status === 'rendering' ? tc('Generando PNG del certificado…') : null} {status === 'downloaded' ? tc('PNG descargado.') : null} {status === 'copied' ? tc('Texto de LinkedIn copiado.') : null} {status === 'missing-lib' ? tc('html2canvas no cargado.') : null} {status === 'missing-ref' ? tc('Referencia del certificado no encontrada.') : null} {status === 'error' ? tc('No se pudo generar el certificado.') : null} {status === 'copy-error' ? tc('No se pudo copiar el texto.') : null} {status === 'idle' ? tc('Descarga un PNG listo para redes o copia el texto para LinkedIn.') : null}
); } function StarPicker(props) { return (
{[1,2,3,4,5].map(function(value) { return ( ); })}
); } function FeedbackGate(props) { var _form = useState({ stars: { experience: 0, content: 0, difficulty: 0 }, nps: null, improve: '', love: '' }), form = _form[0], setForm = _form[1]; var _submit = useState('idle'), submitState = _submit[0], setSubmitState = _submit[1]; var isValid = form.stars.experience > 0 && form.stars.content > 0 && form.stars.difficulty > 0 && form.nps != null; function setStar(key, value) { setForm(function(prev) { return Object.assign({}, prev, { stars: Object.assign({}, prev.stars, { [key]: value }) }); }); } function setField(key, value) { setForm(function(prev) { return Object.assign({}, prev, { [key]: value }); }); } function submit(e) { e.preventDefault(); if (!isValid || !props.onSubmit) return; setSubmitState('submitting'); Promise.resolve(props.onSubmit({ stars: { experience: form.stars.experience, content: form.stars.content, difficulty: form.stars.difficulty }, nps: form.nps, improve: form.improve, love: form.love })).then(function() { setSubmitState('done'); }).catch(function() { setSubmitState('error'); }); } return (
{tc('Cisco Arena · desbloqueo final')}

{tc('Cuéntanos sobre la experiencia')}

{tc('Comparte feedback rápido para desbloquear tu certificado y tarjeta lista para LinkedIn.')}

{tc('Poco probable')}{form.nps != null ? form.nps : '—'}{tc('Sin duda')}
{[0,1,2,3,4,5,6,7,8,9,10].map(function(n) { return {n}; })}
{submitState === 'idle' ? tc('Las calificaciones y NPS son obligatorias. Los comentarios son opcionales.') : null} {submitState === 'done' ? tc('Feedback guardado — certificado listo.') : null} {submitState === 'error' ? tc('No se pudo enviar el feedback. Inténtalo de nuevo.') : null}
); } window.ArenaCertificate = ArenaCertificate; window.CertificateActions = CertificateActions; window.FeedbackGate = FeedbackGate; })();