Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/mailchimp sync screen #1633

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const SettingsMenu = ({ mobilization, widget, location }) => {
widget.id
);
const donationFinishPath = paths.donationFinish(mobilization.id, widget.id);
const sync = paths.sync(mobilization.id, widget.id);

return (
<SettingsPageMenuLayout
Expand Down Expand Up @@ -65,6 +66,16 @@ const SettingsMenu = ({ mobilization, widget, location }) => {
/>
}
/>
<Tab
path={sync}
isActive={sync === location.pathname}
text={
<FormattedMessage
id="Mailchimp Sync"
defaultMessage="Sincronizar"
/>
}
/>
</Tabs>
</SettingsPageMenuLayout>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export const donation = (mid, wid) => prefix(mid, wid, 'donation')
export const donationAutofire = (mid, wid) => prefix(mid, wid, 'donation/autofire')
export const donationExport = (mid, wid) => prefix(mid, wid, 'donation/export')
export const donationFinish = (mid, wid) => prefix(mid, wid, 'donation/finish')
export const sync = (mid, wid) => prefix(mid, wid, 'donation/sync')
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const SettingsMenu = ({ mobilization, widget, location }) => {
const formAutofirePath = paths.formAutofire(mobilization.id, widget.id);
const formExportPath = paths.formExport(mobilization.id, widget.id);
const finishPath = paths.widgetFormSettingsFinish(mobilization.id, widget.id);
const sync = paths.widgetFormSync(mobilization.id, widget.id);

return (
<SettingsPageMenuLayout
Expand Down Expand Up @@ -72,6 +73,16 @@ const SettingsMenu = ({ mobilization, widget, location }) => {
/>
}
/>
<Tab
path={sync}
isActive={sync === location.pathname}
text={
<FormattedMessage
id="MailchimpSync"
defaultMessage="Sincronizar"
/>
}
/>
</Tabs>
</SettingsPageMenuLayout>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('client/mobilizations/widgets/__plugins__/form/components/settings-menu
});
it('should render 5 <Tab /> components as a children', () => {
const wrapper = shallow(<SettingsMenu {...props} />);
expect(wrapper.find('Tab')).to.have.length(5);
expect(wrapper.find('Tab')).to.have.length(6);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export const formAutofire = (mid, wid) => prefix(mid, wid, 'form/autofire')
export const formExport = (mid, wid) => prefix(mid, wid, 'form/export')
export const fieldsMobilizationWidget = (mid, wid) => prefix(mid, wid, 'form/fields')
export const widgetFormSettingsFinish = (mid, wid) => prefix(mid, wid, 'form/finish')
export const widgetFormSync = (mid, wid) => prefix(mid, wid, 'form/sync')
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { Button, Flex, Heading, Stack, Text, useToast } from "bonde-components/chakra";
import React, { useContext } from "react";
import { MailchimpStart } from './mailchimpSync/types';
import { useQuery, useMutation, gql, Context as SessionContext } from 'bonde-core-tools';
import type { Widget } from "./mailchimpSync/FetchWidgets";
import SettingsForm from './mailchimpSync/SettingsForm';
import MailchimpIcon from './mailchimpSync/MailchimpIcon'

interface SyncProps {
widget: Widget
updateCache: (updated: Widget) => void
}

const fetchGraphqlMutation = gql`
mutation($id:Int!, $is_community:Boolean!) {
resync_mailchimp_start(
is_community: $is_community
id: $id
) {
status
}
}
`
const fetchGraphqlQuery = gql`
query($id:Int!, $is_community:Boolean!) {
resync_mailchimp_status(
is_community: $is_community
id: $id
) {
completed
failed
last_sync
waiting
active
status
}
}
`

const lastSync = (last_sync: any) => {
if (typeof last_sync === 'undefined' || last_sync === "") {
return "";
}
return `Data da última atualização: ${last_sync}`;
}

const total = (data: any) => {
return (data.resync_mailchimp_status.waiting +
data?.resync_mailchimp_status.completed +
data?.resync_mailchimp_status.failed +
data?.resync_mailchimp_status.active);
}

//TODO: VER FORCESYNC.TSX
const Sync: React.FC<SyncProps> = ({ widget, updateCache }) => {
const toast = useToast()

const community: any = useContext(SessionContext);

const [setPropagating] = useMutation(
fetchGraphqlMutation,
{ variables: { is_community: false, id: widget?.id } }
);

const { data, loading, error } = useQuery(
fetchGraphqlQuery,
{
variables: { is_community: false, id: widget?.id },
pollInterval: 5000,
},
)

const sync = async () => {
// console.log("DATA", data)
const a: MailchimpStart = await setPropagating();
if (typeof a !== 'undefined' &&
typeof a.data?.resync_mailchimp_start.status !== 'undefined' &&
a.data?.resync_mailchimp_start.status === 'started to add contacts to the queue') {
toast({ title: `Ae! Sincronização em andamento.`, status: 'success', isClosable: true });
} else {
toast({ title: 'Ish! Ocorreu um erro, tente sincronizar novamente.', description: `Se o problema persistir, contate o suporte. ${a.data?.resync_mailchimp_start.status}` });
}
};

//TODO: MENSAGEM "PRECISA CONFIGURAR MAILCHIMP NA COMUNIDADE"
if (!community.mailchimp_api_key || !community.mailchimp_list_id) {
return (
<Stack direction="row" spacing={7} bg="white" p={6} maxW={742}>
<MailchimpIcon />
<Flex maxW={531}>
<Stack spacing={6}>
<Stack spacing={2}>
<Heading as="h3" size="xl">Mailchimp</Heading>
<Text>Sincronize os contatos com o Mailchimp para se comunicar com as pessoas que agiram na sua campanha.</Text>
</Stack>
<Stack>
<Heading as="h4" size="lg">Forçar sincronização</Heading>
<Text>A base de contatos dessa ferramenta não está atualizada no Mailchimp? Tudo bem! Clique em sincronizar pra dar um empurrãozinho:</Text>
</Stack>
<Flex justifyContent="flex-end">
<Button onClick={sync} disabled type='submit' marginTop={4}>Sincronizar</Button>
</Flex>
</Stack>
</Flex>
</Stack>
)
}

if (loading) {
return <Text>Carregando Mailchimp Status</Text>;
} else if (error) {
console.log("ForceSync err: ", error);
return (
<Stack>
<Text>Ish! Ocorreu um erro e no momento não conseguimos retornar o status da sincronização.</Text>
<Text>Se o problema persistir, contacte o suporte.</Text>
</Stack>
);
}


if (data?.resync_mailchimp_status.waiting > 0) {
return (
<Stack>
<Heading as="h4" size="sm">Forçar sincronização</Heading>
<Text>Sua base no Mailchimp não está atualizada? Tudo bem! Clique em sincronizar pra dar um empurrãozinho:</Text>
<Heading as="h4" size="sm">Status</Heading>
<Text size="sm">{data?.resync_mailchimp_status.status} ({data.resync_mailchimp_status.completed} de {total(data)})</Text>
<Flex justifyContent="flex-end">
<Button onClick={sync} disabled type='button' marginTop={4}>Sincronizar</Button>
</Flex>
</Stack>
);
}

return (
<SettingsForm
widget={widget}
afterSubmit={async (values: any, result: any) => {
updateCache(result.data.update_widgets.returning[0])
}}
initialValues={{
settings: {
...widget.settings
}
}}
>
{() => (
<Stack direction="row" spacing={7} bg="white" p={6} maxW={742}>
<MailchimpIcon />
<Flex maxW={531}>
<Stack spacing={6}>
<Stack spacing={2}>
<Heading as="h3" size="xl">Mailchimp</Heading>
<Text>Sincronize os contatos com o Mailchimp para se comunicar com as pessoas que agiram na sua campanha.</Text>
</Stack>
<Stack>
<Heading as="h4" size="lg" >Forçar sincronização</Heading>
<Text>A base de contatos dessa ferramenta não está atualizada no Mailchimp? Tudo bem! Clique em sincronizar pra dar um empurrãozinho:</Text>
</Stack>
<Flex justifyContent="flex-end">
<Button onClick={sync} type='submit' marginTop={4}>Sincronizar</Button>
</Flex>
<Heading as="h4" size="lg">Status</Heading>
<Text>{data?.resync_mailchimp_status.status}</Text>
<Text size="sm">{lastSync(data?.resync_mailchimp_status.last_sync)}</Text>
</Stack>
</Flex>
</Stack>
)}
</SettingsForm>
);
}

export default Sync
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export { default as WidgetOverlay } from './widget-overlay'
export { default as FinishMessageCustom } from './finish-message-custom'
export { default as FormAutofire } from './form-autofire'
export { default as DataExport } from './data-export'
export { default as Sync } from './Sync'
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React from 'react';
import { gql, useQuery } from 'bonde-core-tools';
import { Hint, Loading } from 'bonde-components';
import styled from 'styled-components';

const widgetsByCommunityGQL = gql`
query FetchWidgets ($communityId: Int!) {
widgets (
where: {
_and: [
{ kind: { _neq: "draft" }},
{ kind: { _neq: "content" }},
{
block: {
mobilization: {
deleted_at: { _is_null: true },
community_id: { _eq: $communityId }
}
}
}
]
}
) {
id
kind
settings
created_at
block {
mobilization {
image: facebook_share_image
name
community_id
id
}
}
groups: pressure_targets {
id
targets
identify
label
email_subject
email_body
}

actions: activist_actions_aggregate {
aggregate {
count
}
}
}
}
`

export type Widget = {
id: number
kind: 'pressure' | 'form' | 'donation' | 'plip'
block: {
mobilization: {
image?: string
name: string
community_id: number
id: number
}
}
groups: {
id: number
targets: string[]
identify: string
label: string
email_subject?: string
email_body?: string
}[]
actions: {
aggregate: {
count: number
}
}
created_at: string
settings: Record<string, any>
}

export type RenderProps = {
widgets: Widget[]
loading: boolean
refetch: any
}

const WidgetLoadingStyled = styled.div`
width: 100%;
display: flex;
align-items: center;
justify-content: center;
`

export const WidgetLoading: React.FC = () => (
<WidgetLoadingStyled>
<Loading message='Carregando ações...' />
</WidgetLoadingStyled>
)


type Props = {
communityId: number
children: ({ widgets }: RenderProps) => any
}

const FetchWidgets: React.FC<Props> = ({ children, communityId }) => {
const { data, loading, error, refetch } = useQuery(widgetsByCommunityGQL, { variables: { communityId } });

if (error) return <Hint color="error">{JSON.stringify(error)}</Hint>;

return children({ widgets: data?.widgets || [], refetch, loading });
}

export default FetchWidgets;

Large diffs are not rendered by default.

Loading