The 2026 RNZAF Avionics Trades Reunion has been cancelled. We thank everyone who expressed
interest. Please get in touch with the committee if you have any questions.
Christchurch · 2026
);
const StatsStrip = () => {
const STATS = [
{
num: "5,290",
label: "Airmen Trained",
desc: "Across 288 wireless and radar courses run through WW2.",
},
{
num: "88",
unit: "yrs",
label: "Of Avionics Training",
desc: "From the Electrical & Wireless School, 4 January 1938.",
},
{
num: "5",
unit: "→ 1",
label: "Trades Amalgamated",
desc: "Electrical, Instrument, Ground Radio, Air Radio and Radar Fitters.",
},
{
num: "50",
unit: "yrs",
label: "Since Amalgamation",
desc: "The September 1976 restructure that defined today's trade.",
},
];
return (
A small selection from the 2002 and 2018 reunion archives and the Air Force Museum
collection. Hover an image for caption details.
{ITEMS.map((it, i) => (
{it.year}{it.label}
))}
);
};
const PastReunions = () => {
const PAST = [
{
year: "2002",
title: "Auckland Reunion",
where: "Auckland · 15-17 March 2002",
tag: "First combined Avionics reunion",
body: "The first large gathering of the amalgamated Avionics trade — held in Auckland over three days. Friday night venue was the old 3 Sqn hangar at Hobsonville, and the Saturday night function was held at the Alexandra racecourse. Over 500 attended; more than four hundred training course photographs were collected.",
img: "assets/photos/wigram-10.jpg",
},
{
year: "2018",
title: "80th Anniversary",
where: "Air Force Museum · Wigram",
tag: "1938 — 2018",
body: "Held on Friday 23rd and Saturday 24th March 2018 to mark eighty years since the founding of the Electrical and Wireless School. The 80th-anniversary mark, designed for that reunion, is still in use today.",
img: "assets/photos/wigram-12.png",
},
];
return (
Service Record · Past Reunions
Previous Gatherings
Earlier reunions have been the seed of the collection now preserved in the photo archive.
{PAST.map((p) => (
{p.year}
{p.title}
{p.body}
))}
2002 · Auckland2018 · 80 Years2026 · Cancelled
);
};
const ContactForm = () => {
const [submitted, setSubmitted] = React.useState(false);
const [loading, setLoading] = React.useState(false);
const [serverError, setServerError] = React.useState("");
const [name, setName] = React.useState("");
const [email, setEmail] = React.useState("");
const [message, setMessage] = React.useState("");
const [errors, setErrors] = React.useState({});
const validate = () => {
const e = {};
if (!name.trim()) e.name = "Name is required";
if (!email.trim()) {
e.email = "Email is required";
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
e.email = "Please enter a valid email address";
}
if (!message.trim()) e.message = "Message is required";
return e;
};
const handle = async (e) => {
e.preventDefault();
setServerError("");
const errs = validate();
if (Object.keys(errs).length) {
setErrors(errs);
return;
}
setErrors({});
setLoading(true);
try {
const res = await fetch("https://formsubmit.co/ajax/contact@rnzafavionicsreunion.co.nz", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify({
name,
email,
message,
_subject: "RNZAF Avionics Reunion — Contact from " + name,
}),
});
const data = await res.json();
if (data.success === "true" || data.success === true) {
setSubmitted(true);
} else {
setServerError("Something went wrong. Please try again or email us directly.");
}
} catch {
setServerError("Could not send message. Please email us directly.");
} finally {
setLoading(false);
}
};
if (submitted) {
return (
✓
Message received
Thank you, {name || "there"}.
Your message has been sent to the committee.
);
}
return (
Get in touch
Contact the Committee
For any questions about the reunion or the association, send a message using the form
below
{/* or email us directly at{" "}
contact@rnzafavionicsreunion.co.nz */}
.
);
};
const LINKS = [
{ label: "Air Force Museum of New Zealand", href: "https://www.airforcemuseum.co.nz/" },
{ label: "RNZAF Website", href: "https://www.nzdf.mil.nz/air-force/" },
{
label: "Air Force News (PDF)",
href: "https://www.airforce.mil.nz/about-us/news/airforce-news/pdfs.htm",
},
];
const LinksFooter = () => (
);
function setupSidebar() {
const sidebar = document.querySelector(".rar-sidebar");
if (!sidebar) return;
const nav = sidebar.querySelector("nav");
const allItems = Array.from(nav.querySelectorAll('a[href^="#"]')).filter((a) =>
a.classList.contains("dial-item"),
);
if (allItems.length === 0) return;
// Smooth scroll for clicks
allItems.forEach((a) => {
a.addEventListener("click", function (e) {
e.preventDefault();
const id = this.getAttribute("href").slice(1);
const el = document.getElementById(id);
if (el) window.scrollTo({ top: el.offsetTop - 80, behavior: "smooth" });
});
});
// Build map of section IDs to their items
const buildMap = () => {
const map = new Map();
allItems.forEach((a, idx) => {
const id = a.getAttribute("href").slice(1);
const el = document.getElementById(id);
if (el) map.set(idx, { anchor: a, el, id });
});
return map;
};
let sectionMap = buildMap();
let retries = 0;
const maxRetries = 12;
const startDial = (sectionMap) => {
if (sectionMap.size === 0) return;
const sections = Array.from(sectionMap.values()).sort((a, b) => {
const aIdx = Array.from(sectionMap.entries()).find((e) => e[1] === a)[0];
const bIdx = Array.from(sectionMap.entries()).find((e) => e[1] === b)[0];
return aIdx - bIdx;
});
let ticking = false;
const viewportCenter = () => window.innerHeight / 2;
function updateDial() {
const vc = viewportCenter();
let bestIdx = 0;
let bestDist = Infinity;
// Find section closest to viewport center
sections.forEach((s, idx) => {
const r = s.el.getBoundingClientRect();
const center = r.top + r.height / 2;
const dist = Math.abs(center - vc);
if (dist < bestDist) {
bestDist = dist;
bestIdx = idx;
}
});
// Update all items with dial classes
sections.forEach((s, idx) => {
const offset = idx - bestIdx;
s.anchor.classList.remove(
"dial-center",
"dial-offset-1",
"dial-offset-neg-1",
"dial-offset-2",
"dial-offset-neg-2",
"hidden",
);
// Only show items within ±2 range
if (Math.abs(offset) > 2) {
s.anchor.classList.add("hidden");
} else if (offset === 0) {
s.anchor.classList.add("dial-center");
} else if (offset === 1) {
s.anchor.classList.add("dial-offset-1");
} else if (offset === -1) {
s.anchor.classList.add("dial-offset-neg-1");
} else if (offset === 2) {
s.anchor.classList.add("dial-offset-2");
} else if (offset === -2) {
s.anchor.classList.add("dial-offset-neg-2");
}
});
}
function onScroll() {
if (ticking) return;
ticking = true;
requestAnimationFrame(() => {
updateDial();
ticking = false;
});
}
window.addEventListener("scroll", onScroll, { passive: true });
window.addEventListener("resize", onScroll);
updateDial();
};
if (sectionMap.size === 0) {
const id = setInterval(() => {
retries += 1;
sectionMap = buildMap();
if (sectionMap.size > 0 || retries >= maxRetries) {
clearInterval(id);
if (sectionMap.size > 0) startDial(sectionMap);
}
}, 100);
} else {
startDial(sectionMap);
}
}
Object.assign(window, {
Header,
Hero,
AnnouncementPanel,
StatsStrip,
Chapter,
PullQuote,
Gallery,
PastReunions,
ContactForm,
LinksFooter,
setupSidebar,
});