All files / src/components/organizer/EventPage EventCommunicationsContainer.tsx

100% Statements 9/9
71.42% Branches 10/14
100% Functions 3/3
100% Lines 9/9

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110                                                                    1x       6x 6x 6x 6x         6x                                             6x         2x           24x                                                          
/**
 * EventCommunicationsContainer (Epic 14 โ€” Communications tab)
 *
 * The single Communications surface. An audience switch over four audiences โ€”
 * ๐Ÿ“ฐ Newsletter subscribers ยท ๐ŸŽŸ๏ธ Event registrants ยท ๐ŸŽค Speakers ยท ๐Ÿ›๏ธ Venue &
 * Caterer โ€” each composing with its own existing surface (recompose, not
 * rewrite; NFR9). The Newsletter / Registrant / Venue children are unchanged
 * from Phase A; the Speakers audience (Story 14.E.3) surfaces the previously
 * unwired bulk-reminder hook.
 */
 
import React, { useState } from 'react';
import { Box, Tabs, Tab } from '@mui/material';
import {
  MailOutline as NewsletterIcon,
  ConfirmationNumberOutlined as RegistrantsIcon,
  MicNone as SpeakersIcon,
  StorefrontOutlined as VenueIcon,
} from '@mui/icons-material';
import { useTranslation } from 'react-i18next';
import { useBreakpoints } from '@/hooks/useBreakpoints';
import type { Event, EventDetailUI } from '@/types/event.types';
import { EventNewsletterTab } from './EventNewsletterTab';
import { EventRegistrantNoticesTab } from './EventRegistrantNoticesTab';
import { EventVenueTab } from './EventVenueTab';
import { SpeakerBulkComms } from './SpeakerBulkComms';
 
interface EventCommunicationsContainerProps {
  event: Event | EventDetailUI;
  eventCode: string;
}
 
type CommAudience = 'newsletter' | 'registrant-notices' | 'speakers' | 'venue';
 
export const EventCommunicationsContainer: React.FC<EventCommunicationsContainerProps> = ({
  event,
  eventCode,
}) => {
  const { t } = useTranslation('events');
  const { isMobile } = useBreakpoints();
  const [audience, setAudience] = useState<CommAudience>('newsletter');
  const eventTitle = event.title || '';
 
  // Each audience tab shows icon + label on desktop; on mobile (Phase G) it collapses to
  // icon-only (the four labelled tabs are far too wide for a phone). The label stays in
  // aria-label for screen readers regardless.
  const audiences = [
    {
      value: 'newsletter' as const,
      icon: <NewsletterIcon />,
      label: t('eventPage.communications.audiences.newsletter', 'Newsletter subscribers'),
    },
    {
      value: 'registrant-notices' as const,
      icon: <RegistrantsIcon />,
      label: t('eventPage.communications.audiences.registrants', 'Event registrants'),
    },
    {
      value: 'speakers' as const,
      icon: <SpeakersIcon />,
      label: t('eventPage.communications.audiences.speakers', 'Speakers'),
    },
    {
      value: 'venue' as const,
      icon: <VenueIcon />,
      label: t('eventPage.communications.audiences.venue', 'Venue & Caterer'),
    },
  ];
 
  return (
    <Box>
      <Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 3 }}>
        <Tabs
          value={audience}
          onChange={(_e, v: CommAudience) => setAudience(v)}
          aria-label={t('eventPage.tabs.communications', 'Communications')}
          variant="scrollable"
          scrollButtons="auto"
        >
          {audiences.map((a) => (
            <Tab
              key={a.value}
              value={a.value}
              icon={a.icon}
              iconPosition="start"
              label={isMobile ? undefined : a.label}
              aria-label={a.label}
              data-testid={`comms-subtab-${a.value}`}
              sx={isMobile ? { minWidth: 0 } : undefined}
            />
          ))}
        </Tabs>
      </Box>
 
      {audience === 'newsletter' && (
        <EventNewsletterTab eventCode={eventCode} eventTitle={eventTitle} />
      )}
      {audience === 'registrant-notices' && (
        <EventRegistrantNoticesTab eventCode={eventCode} eventTitle={eventTitle} />
      )}
      {audience === 'speakers' && (
        <SpeakerBulkComms eventCode={eventCode} eventTitle={eventTitle} />
      )}
      {audience === 'venue' && <EventVenueTab event={event} />}
    </Box>
  );
};
 
export default EventCommunicationsContainer;