Calendario de Discourse (y evento)

:partying_face: Este plugin ahora está incluido en el núcleo de Discourse como parte de Bundling more popular plugins with Discourse core. Si te autoalojas y usas el plugin, necesitas eliminarlo de tu app.yml antes de tu próxima actualización.

2 Me gusta

Claro, aquí tienes la versión revisada, un poco más amigable y abierta para tu publicación en inglés:


Realmente necesitamos la capacidad de limitar el número de participantes para los eventos, ya que muchos de nuestros eventos tienen capacidad limitada.

Actualmente, el sistema de eventos no nos permite:

  • establecer un número máximo de participantes,
  • ver quién se registró primero (sin marcas de tiempo de registro),
  • gestionar una lista de espera o notificar a las personas cuando se abre un lugar.

Nos serían muy útiles las siguientes funciones:

  1. Un límite de participantes (cap) que impida que más usuarios se registren una vez que esté lleno.
  2. Una lista de espera para aquellos que aún desean asistir una vez que el evento esté completo.
  3. Notificaciones automáticas cuando un lugar esté disponible.
  4. Marcas de tiempo opcionales para ver el orden de los registros (útil para una priorización justa).

Esto sería increíblemente útil para las comunidades que organizan eventos presenciales o con capacidad limitada.

¿Hay algo como esto ya planeado o en desarrollo?
¿O existen soluciones alternativas conocidas para este caso de uso?

¡Muchas gracias de antemano!

4 Me gusta

Gracias Aurora — ¡realmente me entusiasma saber que el trabajo del calendario nativo está activo de nuevo!

También nos gustaría destacar una solicitud adicional de alto impacto que ha surgido en varias discusiones comunitarias: la sincronización de feeds iCal.

Esto se desglosó en su propio tema dedicado aquí:

La capacidad de suscribirse a feeds .ics externos (como horarios escolares, calendarios cívicos o eventos organizacionales) y que se reflejen en un calendario de temas de Discourse haría que esta función sea mucho más útil para muchas implementaciones del mundo real. Sin ella, nos vemos obligados a copiar manualmente los eventos, lo cual es propenso a errores y difícil de mantener.

Agradeceríamos enormemente cualquier comentario del equipo de Discourse sobre si partes de esa propuesta —como la sincronización iCal unidireccional, la configuración del intervalo de actualización del feed o el etiquetado opcional de eventos— están dentro del alcance de la próxima implementación.

De cualquier manera, ¡gracias de nuevo por dar nueva vida a Discourse Calendar — esperamos con ansias lo que está por venir!

4 Me gusta

Si deseas mostrar el botón “Crear evento” directamente desde el editor, como se muestra a continuación, utiliza el siguiente código en el encabezado de tu tema. Ve a admin > apariencia > tema > editar > editar código > head (asegúrate de que esté colocado entre las etiquetas <head>).

Probado en discourse 3.5.0.beta9-dev en escritorio con Firefox.

 <!-- Botón personalizado para crear eventos (basado en icono, a prueba de idiomas) -->
<script>
(() => {
  const composerSelector = ".d-editor-button-bar";
  const menuTriggerSelector = ".btn.no-text.fk-d-menu__trigger.toolbar-menu__options-trigger.toolbar__button.options.toolbar-popup-menu-options";
  const menuContentSelector = ".fk-d-menu__inner-content";
  const menuModalSelector = ".d-modal.fk-d-menu-modal";

  // Función para encontrar el botón del calendario existente
  const findCalendarButton = (container) => {
    const calendarIcon = container.querySelector('svg use[href="#calendar-day"]');
    return calendarIcon ? calendarIcon.closest("button") : null;
  };

  // Función para esperar a que un elemento aparezca o desaparezca
  const waitForElement = (selector, findFn, timeout = 4000) =>
    new Promise((resolve, reject) => {
      const element = findFn(selector);
      if (element) return resolve(element);

      const observer = new MutationObserver(() => {
        const foundElement = findFn(selector);
        if (foundElement) {
          observer.disconnect();
          resolve(foundElement);
        }
      });
      observer.observe(document.body, { childList: true, subtree: true });
      setTimeout(() => {
        observer.disconnect();
        reject(new Error("Element not found within timeout"));
      }, timeout);
    });

  // Función para esperar a que aparezca el modal del menú
  const waitForMenuModal = (timeout = 4000) => {
    const observer = new MutationObserver(() => {
      if (document.querySelector(menuModalSelector)) {
        observer.disconnect();
      }
    });
    observer.observe(document.body, { childList: true, subtree: true });
    setTimeout(() => observer.disconnect(), timeout);
  };

  // Función para añadir el botón personalizado
  const addCustomCreateEventButton = (container) => {
    if (container.querySelector(".custom-create-event-btn")) return;

    const newButton = document.createElement("button");
    newButton.className = "btn no-text btn-icon toolbar__button link custom-create-event-btn";
    newButton.title = "Crear evento";
    newButton.innerHTML = `
      <svg class="fa d-icon d-icon-calendar-day svg-icon">
        <use href="#calendar-day"></use>
      </svg>
    `;
    container.appendChild(newButton);

    newButton.addEventListener("click", async () => {
      const trigger = document.querySelector(menuTriggerSelector);
      if (!trigger) return;
      trigger.click();

      let menuContent = document.querySelector(menuContentSelector);
      if (!menuContent) {
        await new Promise((resolve, reject) => {
          const observer = new MutationObserver(() => {
            menuContent = document.querySelector(menuContentSelector);
            if (menuContent) {
              observer.disconnect();
              resolve();
            }
          });
          observer.observe(document.body, { childList: true, subtree: true });
          setTimeout(() => {
            observer.disconnect();
            reject(new Error("Menu content not found within timeout"));
          }, 2000);
        });
      }

      try {
        await waitForElement(menuContentSelector, (selector) => document.querySelector(selector), 5000);
        const calendarButton = findCalendarButton(document.querySelector(menuContentSelector));
        if (calendarButton) {
          calendarButton.click();
          waitForMenuModal();
        }
      } catch (error) {
        console.error("Error clicking calendar button:", error);
      }
    });
  };

  // Observador para detectar la aparición del composer
  const composerObserver = new MutationObserver(() => {
    const composer = document.querySelector(composerSelector);
    if (composer) {
      addCustomCreateEventButton(composer);
    }
  });
  composerObserver.observe(document.body, { childList: true, subtree: true });

  // Comprobar si el composer ya está presente al cargar la página
  const initialComposer = document.querySelector(composerSelector);
  if (initialComposer) {
    addCustomCreateEventButton(initialComposer);
  }
})();
</script>

He intentado ejecutar el script, el botón de creación de eventos se crea correctamente, pero cuando hago clic en él, obtengo el mismo menú contextual que el botón de más. Quizás hice algo mal.

1 me gusta

Después de la actualización ha mejorado, al menos solo aparece “Crear evento”

La captura de pantalla está en alemán, lo siento.

Hola,

Esto funciona en la última versión con 3.5.0.beta9-dev, ¿no sé cuál es tu versión?

Y esto es javascript, así que deberías proporcionar el error de JS de la consola cuando presiones F12 en tu navegador.

Tengo la misma versión 3.5.0.beta9-dev
este es el mensaje de la consola


Debo estar haciendo algo mal :sweat_smile:

No uso Edge, ¿puedes intentarlo de nuevo con el script que acabo de actualizar en la publicación original, ya que encontré errores que corregí? Si no funciona, lo actualizaré más tarde después de instalar Edge.

He actualizado el script para que sea más compatible con dispositivos móviles, debería funcionar ahora, por favor copia y pega el script de la publicación original

Confirmo que el código actualizado funciona bien en el borde. Si tienes algo como ublock, siempre puedes deshabilitarlo para tu página de discourse, pero no creo que esté relacionado.

Lo siento, sigo teniendo el mismo problema, debo estar haciendo algo mal

Sin embargo, pego tu script aquí

1 me gusta

De acuerdo, gracias a la situación de Gilles, pude configurar un selector basado en la clase .svg del icono que es único en lugar de un atributo de título que variaría según el idioma, el script ahora también está minificado y envuelto en IIFE.

Puede encontrar el script actualizado aquí Discourse Calendar (and Event) - #535 by opcourdis

1 me gusta

Gracias por tu ayuda :+1:

1 me gusta

Sería de gran ayuda tener tu script encapsulado como un Theme component, y que las categorías donde se aplica sean seleccionables.

El caso de uso que tengo en mente es una categoría de ‘Eventos’, donde quiero hacer que la publicación de eventos sea súper obvia.

1 me gusta

Puedes usar lo que está abajo y modificar las primeras condiciones para especificar tus categorías, y para que el botón sea más visible, CSS lo hará: .btn.no-text.btn-icon.toolbar__button.link.custom-create-event-btn {
order: -1;
}

<script>(()=>{if(!(document.body.classList.contains("category-events")||document.body.classList.contains("category-event2")||document.body.classList.contains("category-event3")))return;const e=".d-editor-button-bar",t=".btn.no-text.fk-d-menu__trigger.toolbar-menu__options-trigger.toolbar__button.options.toolbar-popup-menu-options",n=".fk-d-menu__inner-content",o=".d-modal.fk-d-menu-modal",c=e=> {const t=e.querySelector('svg use[href="#calendar-day"]');return t?t.closest("button"):null},r=(e,t,n=4e3)=>new Promise((o,c)=>{const r=t(e);if(r)return o(r);const l=new MutationObserver(()=> {const n=t(e);n&& (l.disconnect(),o(n))});l.observe(e,{childList:!0,subtree:!0}),setTimeout(()=> {l.disconnect(),c()},n)}),l=(e=4e3)=> {const t=new MutationObserver(()=> {document.querySelector(o)&&t.disconnect()});t.observe(document.body,{childList:!0,subtree:!0}),setTimeout(()=>t.disconnect(),e)},s=e=> {if(e.querySelector(".custom-create-event-btn"))return;const o=document.createElement("button");o.className="btn no-text btn-icon toolbar__button link custom-create-event-btn",o.title="Create event",o.innerHTML='<svg class="fa d-icon d-icon-calendar-day svg-icon"><use href="#calendar-day"></use></svg>',e.appendChild(o),o.addEventListener("click",async()=> {const e=document.querySelector(t);if(!e)return;e.click();let o=document.querySelector(n);o||(await new Promise((e,t)=> {const c=new MutationObserver(()=> {o=document.querySelector(n)&&c.disconnect(),e()});c.observe(document.body,{childList:!0,subtree:!0}),setTimeout(()=> {c.disconnect(),t()},2e3)}));try{(await r(o,c)).click(),l()}catch{}})},u=new MutationObserver(()=> {const t=document.querySelector(e);t&&s(t)});u.observe(document.body,{childList:!0,subtree:!0});const d=document.querySelector(e);d&&s(d)})()}</script>


Gracias por la sugerencia, todavía soy un poco nuevo en discourse y revisaré el componente de tema, la ubicación del botón es mejor, de hecho, pero mi otro script para el límite de participantes de eventos podría no ser necesario pronto debido a esto https://github.com/discourse/discourse/pull/34313```
4 Me gusta

Después de actualizar a la última versión de Discourse y al plugin discourse-calendar, estoy viendo la siguiente advertencia como administrador:

⚠️ Es posible que las publicaciones no se muestren correctamente porque uno de los decoradores de contenido de publicaciones en su sitio generó un error.
Causado por el plugin 'discourse-calendar'
(este mensaje solo se muestra a los administradores del sitio)
  • El plugin del calendario ya no funciona: el contenido del calendario y los eventos no se muestran en los temas.
  • El plugin funcionaba correctamente antes de la reciente actualización.
  • Mi sitio de Discourse y todos los plugins oficiales están ahora actualizados.

Estamos utilizando el plugin Discourse Post Event en nuestro foro.
Actualmente, cuando un usuario se une (confirma asistencia) a un evento, el tema se establece automáticamente en “Seguimiento”, lo que significa que cada nueva respuesta al tema del evento activa una notificación para todos los participantes.

Nos gustaría mantener el nivel de notificación como “Normal” por defecto, incluso después de que alguien se una a un evento.

He revisado la configuración del sitio pero no he encontrado una opción que funcione.
¿Hay alguna forma de deshabilitar o cambiar este comportamiento automático de “Seguimiento” cuando los usuarios confirman asistencia a un evento?

No lo creo. Pero esta sería una solicitud de función útil.

Una solución alternativa útil podría ser cerrar el tema para detener las respuestas, pero tener un canal de chat asociado a él (estos no notifican por defecto).

La etiqueta del botón “Hoy” puede ser engañosa.

El botón en realidad no navega al día actual, sino que navega a la vista actual de la pestaña de marco de tiempo activa (Día/Semana/Mes/Año). En Día, Semana y Mes, esto sí muestra el día actual. Pero en Año, solo navega al año actual (que siempre comienza en enero).

Probablemente debería ser

  • renombrado para describir con mayor precisión su funcionalidad, como “Actual”
  • o, quizás mejor, no solo navegar al año actual, sino desplazarse al día actual en la lista de Año.
1 me gusta