'use client'; import { AddProviderButton } from '@gitroom/frontend/components/launches/add.provider.component'; import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import Image from 'next/image'; import { groupBy, orderBy } from 'lodash'; import { CalendarWeekProvider } from '@gitroom/frontend/components/launches/calendar.context'; import { Filters } from '@gitroom/frontend/components/launches/filters'; import { useFetch } from '@gitroom/helpers/utils/custom.fetch'; import useSWR from 'swr'; import { LoadingComponent } from '@gitroom/frontend/components/layout/loading'; import clsx from 'clsx'; import { useUser } from '../layout/user.context'; import { Menu } from '@gitroom/frontend/components/launches/menu/menu'; import { useRouter, useSearchParams } from 'next/navigation'; import { Integration } from '@prisma/client'; import ImageWithFallback from '@gitroom/react/helpers/image.with.fallback'; import { useToaster } from '@gitroom/react/toaster/toaster'; import { useFireEvents } from '@gitroom/helpers/utils/use.fire.events'; import { Calendar } from './calendar'; import { useDrag, useDrop } from 'react-dnd'; import { DNDProvider } from '@gitroom/frontend/components/launches/helpers/dnd.provider'; import { GeneratorComponent } from './generator/generator'; import { useVariables } from '@gitroom/react/helpers/variable.context'; import { NewPost } from '@gitroom/frontend/components/launches/new.post'; import { useT } from '@gitroom/react/translation/get.transation.service.client'; interface MenuComponentInterface { refreshChannel: ( integration: Integration & { identifier: string; } ) => () => void; continueIntegration: (integration: Integration) => () => void; totalNonDisabledChannels: number; mutate: (shouldReload?: boolean) => void; update: (shouldReload: boolean) => void; } export const OpenClose: FC<{ isOpen: boolean; }> = (props) => { const { isOpen } = props; return ( ); }; export const MenuGroupComponent: FC< MenuComponentInterface & { changeItemGroup: (id: string, group: string) => void; group: { id: string; name: string; values: Array< Integration & { identifier: string; changeProfilePicture: boolean; changeNickName: boolean; } >; }; } > = (props) => { const { group, mutate, update, continueIntegration, totalNonDisabledChannels, refreshChannel, changeItemGroup, } = props; const [isOpen, setIsOpen] = useState( !!+(localStorage.getItem(group.name + '_isOpen') || '1') ); const changeOpenClose = useCallback( (e: any) => { setIsOpen(!isOpen); localStorage.setItem(group.name + '_isOpen', isOpen ? '0' : '1'); e.stopPropagation(); }, [isOpen] ); const [collectedProps, drop] = useDrop(() => ({ accept: 'menu', drop: ( item: { id: string; }, monitor ) => { changeItemGroup(item.id, group.id); }, collect: (monitor) => ({ isOver: !!monitor.isOver(), }), })); return (
{collectedProps.isOver && (
)} {!!group.name && (
{group.name}
)}
{group.values.map((integration) => ( ))}
); }; export const MenuComponent: FC< MenuComponentInterface & { integration: Integration & { identifier: string; changeProfilePicture: boolean; changeNickName: boolean; refreshNeeded?: boolean; }; } > = (props) => { const { totalNonDisabledChannels, continueIntegration, refreshChannel, mutate, update, integration, } = props; const user = useUser(); const [collected, drag, dragPreview] = useDrag(() => ({ type: 'menu', item: { id: integration.id, }, })); return (
{(integration.inBetweenSteps || integration.refreshNeeded) && (
!
)} {integration.identifier === 'youtube' ? ( ) : ( {integration.identifier} )}
{integration.name}
totalNonDisabledChannels && integration.disabled } canDisable={!integration.disabled} />
); }; export const LaunchesComponent = () => { const fetch = useFetch(); const user = useUser(); const { billingEnabled } = useVariables(); const router = useRouter(); const search = useSearchParams(); const toast = useToaster(); const fireEvents = useFireEvents(); const t = useT(); const [reload, setReload] = useState(false); const load = useCallback(async (path: string) => { return (await (await fetch(path)).json()).integrations; }, []); const { isLoading, data: integrations, mutate, } = useSWR('/integrations/list', load, { fallbackData: [], }); const totalNonDisabledChannels = useMemo(() => { return ( integrations?.filter((integration: any) => !integration.disabled) ?.length || 0 ); }, [integrations]); const changeItemGroup = useCallback( async (id: string, group: string) => { mutate( integrations.map((integration: any) => { if (integration.id === id) { return { ...integration, customer: { id: group, }, }; } return integration; }), false ); await fetch(`/integrations/${id}/group`, { method: 'PUT', body: JSON.stringify({ group, }), }); mutate(); }, [integrations] ); const sortedIntegrations = useMemo(() => { return orderBy( integrations, ['type', 'disabled', 'identifier'], ['desc', 'asc', 'asc'] ); }, [integrations]); const menuIntegrations = useMemo(() => { return orderBy( Object.values( groupBy(sortedIntegrations, (o) => o?.customer?.id || '') ).map((p) => ({ name: (p[0].customer?.name || '') as string, id: (p[0].customer?.id || '') as string, isEmpty: p.length === 0, values: orderBy( p, ['type', 'disabled', 'identifier'], ['desc', 'asc', 'asc'] ), })), ['isEmpty', 'name'], ['desc', 'asc'] ); }, [sortedIntegrations]); const update = useCallback(async (shouldReload: boolean) => { if (shouldReload) { setReload(true); } await mutate(); if (shouldReload) { setReload(false); } }, []); const continueIntegration = useCallback( (integration: any) => async () => { router.push( `/launches?added=${integration.identifier}&continue=${integration.id}` ); }, [] ); const refreshChannel = useCallback( ( integration: Integration & { identifier: string; } ) => async () => { const { url } = await ( await fetch( `/integrations/social/${integration.identifier}?refresh=${integration.internalId}`, { method: 'GET', } ) ).json(); window.location.href = url; }, [] ); useEffect(() => { if (typeof window === 'undefined') { return; } if (search.get('msg')) { toast.show(search.get('msg')!, 'warning'); window?.opener?.postMessage( { msg: search.get('msg')!, success: false, }, '*' ); } if (search.get('added')) { fireEvents('channel_added'); window?.opener?.postMessage( { msg: 'Channel added', success: true, }, '*' ); } if (window.opener) { window.close(); } }, []); if (isLoading || reload) { return ; } // @ts-ignore return (

{t('channels')}

{sortedIntegrations.length === 0 && (
{t('no_channels', 'No channels')}
)} {menuIntegrations.map((menu) => ( ))}
update(true)} /> {sortedIntegrations?.length > 0 && } {sortedIntegrations?.length > 0 && user?.tier?.ai && billingEnabled && }
{process.env.NEXT_PUBLIC_VERSION ? `v${process.env.NEXT_PUBLIC_VERSION}` : ''}
); };