Skip to content
72 changes: 45 additions & 27 deletions events/developer-meetups.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,27 @@ title: DHIS2 Developer Meetups
---

import NextSecondThursday from '@site/src/nextSecondThursday';
import DiscourseEmbed from '@site/src/DiscourseEmbed';

<style>{`.video-container {
position: relative;
padding-bottom: 56.25%; /* 16:9 Aspect Ratio */
height: 0;
border-radius: 8px;
border: 1px solid var(--ifm-color-emphasis-200);
box-shadow: var(--ifm-global-shadow-lw);
margin-bottom: var(--ifm-spacing-vertical);
overflow: hidden;
}

.video-container iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}`}</style>


Did you know that the DHIS2 Developer Community hosts monthly meetups?

Expand All @@ -19,10 +40,21 @@ Topics range from meet and greet to technical web development discussions. These
- DHIS2 application testing with Cypress
- Meet and Greet, general Q&A

## Next Meetup Time & Date

The DHIS2 Developer Meetup is happening every second Thursday of the month.

The next Developer Meetup is on ***<NextSecondThursday />\* at 11:00 CE(S)T\*\*.***
## Next Meetup Time & Date

The next Developer Meetup is on ***<NextSecondThursday />\* at 11:00 CE(S)T\*\*.*** Learn more about the latest meetup in the CoP announcement post. If you missed the meetup, it will be announced in the development category, [register here to receive a notification](https://community.dhis2.org/join-dev-meetup).

<DiscourseEmbed
category="10"
tags="meetup"
perPage="1"
template='basic'
order='created'
loading="Loading the latest Developer Meetup topic"
/>

In other time zones, this is:

Expand All @@ -40,31 +72,17 @@ In other time zones, this is:
**CE(S)T stands for Central European (Summer) Time. This is the time zone in Oslo, Norway, where the DHIS2 Core Team is located. Remember that this time zone is subject to Daylight Saving Time changes and can differ from your time. Always check the calendar invite to ensure you have the correct time.
:::

### Register for the repeating meetup
To join the DHIS2 Developer Meetup, you can [register for the repeating](https://us06web.zoom.us/meeting/register/tZcscOGqrzssGNCTNmlQs8Kay-lJa7TYbQec#/registration) event on Zoom. After registering you will get an invite for all future meetups.

[Register on Zoom to join All Developer Meetups](https://us06web.zoom.us/meeting/register/tZcscOGqrzssGNCTNmlQs8Kay-lJa7TYbQec#/registration).

## Previous Meetups

Sometimes we record the meetups and make them available on the [DHIS2 YouTube channel](https://www.youtube.com/channel/UCQI6z8JL1Z1z8J1ZJX3k9jA). Usually these recordings are community presentations or demos, but also product updates. Find some recordings below, but do check the Developer Meetup playlist on YouTube for more.

### v41 Tracker API and Capture App changes, and Custom Plugins

<iframe width="560" height="315" src="https://www.youtube.com/embed/gqGoRF3ktw4?si=1mjtfIF7VPWzqCuQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

### SEMIS Capture App by Saudigitus

<iframe width="560" height="315" src="https://www.youtube.com/embed/Nuc8vLqRXtc?si=OE403p6EUhhWpqSb" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

### ICD-11 Cause of Death demonstration by HISP Vietnam

<iframe width="560" height="315" src="https://www.youtube.com/embed/6UMhi7_2NSc?si=TkabWw-aBP64YAku" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

### JumpaDokter Ecoystem by HISP Indonesia

<iframe width="560" height="315" src="https://www.youtube.com/embed/-bYYKMor1ow?si=yXjd82N31mOYMoQw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

### Report Builder Demonstration by HISP WCA

<iframe width="560" height="315" src="https://www.youtube.com/embed/cePvIfGAsZo?si=iRtBrRfT_fzkj76q" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
Sometimes we record the meetups and make them available on the [DHIS2 YouTube channel - Developer Meetups playlist](https://www.youtube.com/channel/UCQI6z8JL1Z1z8J1ZJX3k9jA). Usually these recordings are community presentations or demos, but also product updates. Below is the latest meetup recording:

<div className="video-container">
<iframe
src="https://www.youtube.com/embed/videoseries?list=PLo6Seh-066RwjOT8EyrSJHrBmDQd9264e"
title="DHIS2 Developer Meetup Playlist"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerPolicy="strict-origin-when-cross-origin"
allowFullScreen
/>
</div>
85 changes: 85 additions & 0 deletions src/DiscourseEmbed.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React, { useEffect, useRef, useState } from 'react'

export default function DiscourseEmbed({
discourseUrl = 'https://community.dhis2.org',

Check warning on line 4 in src/DiscourseEmbed.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'discourseUrl' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=dhis2_developer-portal&issues=AZ4ld2IT6txHQD_wmvzw&open=AZ4ld2IT6txHQD_wmvzw&pullRequest=217
category,

Check warning on line 5 in src/DiscourseEmbed.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'category' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=dhis2_developer-portal&issues=AZ4ld2IT6txHQD_wmvzx&open=AZ4ld2IT6txHQD_wmvzx&pullRequest=217
tags,

Check warning on line 6 in src/DiscourseEmbed.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'tags' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=dhis2_developer-portal&issues=AZ4ld2IT6txHQD_wmvzy&open=AZ4ld2IT6txHQD_wmvzy&pullRequest=217
perPage = 5,

Check warning on line 7 in src/DiscourseEmbed.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'perPage' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=dhis2_developer-portal&issues=AZ4ld2IT6txHQD_wmvzz&open=AZ4ld2IT6txHQD_wmvzz&pullRequest=217
template = 'complete',

Check warning on line 8 in src/DiscourseEmbed.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'template' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=dhis2_developer-portal&issues=AZ4ld2IT6txHQD_wmvz0&open=AZ4ld2IT6txHQD_wmvz0&pullRequest=217
order = 'created',

Check warning on line 9 in src/DiscourseEmbed.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'order' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=dhis2_developer-portal&issues=AZ4mHdg0UYZaxSTQ7htH&open=AZ4mHdg0UYZaxSTQ7htH&pullRequest=217
loading,

Check warning on line 10 in src/DiscourseEmbed.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'loading' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=dhis2_developer-portal&issues=AZ4ld2IT6txHQD_wmvz1&open=AZ4ld2IT6txHQD_wmvz1&pullRequest=217
}) {
const containerRef = useRef(null)
const [isLoading, setIsLoading] = useState(true)

useEffect(() => {
const handleMessage = (e) => {
if (e.origin !== discourseUrl) return
if (e?.data?.type === 'discourse-resize' && e.data.embedId) {
const iframe = document.getElementById(e.data.embedId)
if (iframe) iframe.style.height = e.data.height + 'px'
}
}

window.addEventListener('message', handleMessage, false)

// II. Iframe Injection Logic
if (
containerRef.current &&
containerRef.current.querySelector('iframe') === null

Check warning on line 29 in src/DiscourseEmbed.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer using an optional chain expression instead, as it's more concise and easier to read.

See more on https://sonarcloud.io/project/issues?id=dhis2_developer-portal&issues=AZ4ld2IT6txHQD_wmvz2&open=AZ4ld2IT6txHQD_wmvz2&pullRequest=217
) {
const frameId = 'de-' + Math.random().toString(36).substr(2, 9)

Check warning on line 31 in src/DiscourseEmbed.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'(from: number, length?: number): string' is deprecated.

See more on https://sonarcloud.io/project/issues?id=dhis2_developer-portal&issues=AZ4ld2IT6txHQD_wmvz4&open=AZ4ld2IT6txHQD_wmvz4&pullRequest=217
const params = new URLSearchParams({
discourse_embed_id: frameId,
category,
tags,
per_page: perPage,
template: template,
order: order
})

const iframe = document.createElement('iframe')
iframe.src = `${discourseUrl}/embed/topics?${params.toString()}`
iframe.id = frameId
iframe.frameBorder = '0'

Check warning on line 44 in src/DiscourseEmbed.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'frameBorder' is deprecated.

See more on https://sonarcloud.io/project/issues?id=dhis2_developer-portal&issues=AZ4ld2IT6txHQD_wmvz5&open=AZ4ld2IT6txHQD_wmvz5&pullRequest=217
iframe.scrolling = 'no'

Check warning on line 45 in src/DiscourseEmbed.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'scrolling' is deprecated.

See more on https://sonarcloud.io/project/issues?id=dhis2_developer-portal&issues=AZ4ld2IT6txHQD_wmvz6&open=AZ4ld2IT6txHQD_wmvz6&pullRequest=217
iframe.style.width = '100%'
iframe.style.height = '600px'
iframe.style.border = '0'
iframe.style.width = '100%'
iframe.style.visibility = 'hidden' // Keep hidden until loaded

// III. The "OnLoad" Handover
iframe.onload = () => {
setIsLoading(false)
iframe.style.visibility = 'visible'
}

containerRef.current.appendChild(iframe)
}

return () => window.removeEventListener('message', handleMessage, false)
}, [discourseUrl, category, tags, perPage, template])

return (
<div
className="discourse-embed-wrapper"
style={{ minHeight: '100px', position: 'relative' }}
>
{isLoading && (
<div
className="discourse-loading-state"
style={{
padding: '20px',
color: 'var(--ifm-color-primary)',
fontWeight: 'bold',
fontStyle: 'italic',
}}
>
{loading || `Loading Developer Meetups' topics...`}
</div>
)}
<div ref={containerRef} className="discourse-topics-container" />
</div>
)
}