Skip to content

Commit

Permalink
Merge pull request #29 from vivid-planet/add-target-group-basic-admin
Browse files Browse the repository at this point in the history
 COM-271: Add target group basic admin files
  • Loading branch information
RainbowBunchie authored Jan 29, 2024
2 parents c92d126 + 31b7542 commit 3089d40
Show file tree
Hide file tree
Showing 15 changed files with 597 additions and 22 deletions.
4 changes: 3 additions & 1 deletion demo/admin/src/Routes.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MasterLayout, RouteWithErrorBoundary } from "@comet/admin";
import { Domain } from "@comet/admin-icons";
import { createBrevoContactsPage } from "@comet/brevo-admin";
import { createBrevoContactsPage, createTargetGroupsPage } from "@comet/brevo-admin";
import { ContentScopeIndicator, createRedirectsPage, DamPage, PagesPage, PublisherPage, SitePreview } from "@comet/cms-admin";
import { getBrevoContactConfig } from "@src/common/brevoModuleConfig/brevoContactsPageAttributesConfig";
import { pageTreeCategories, urlParamToCategory } from "@src/pageTree/pageTreeCategories";
Expand All @@ -19,6 +19,7 @@ import { Page } from "./documents/pages/Page";
import { ProductsPage } from "./products/ProductsPage";

const RedirectsPage = createRedirectsPage();
const TargetGroupsPage = createTargetGroupsPage({ scopeParts: ["domain", "language"] });

export const Routes: React.FC = () => {
const intl = useIntl();
Expand Down Expand Up @@ -75,6 +76,7 @@ export const Routes: React.FC = () => {
/>

<RouteWithErrorBoundary path={`${match.path}/newsletter/contacts`} component={BrevoContactsPage} />
<RouteWithErrorBoundary path={`${match.path}/newsletter/target-groups`} component={TargetGroupsPage} />

<RouteWithErrorBoundary path={`${match.path}/structured-content/products`} component={ProductsPage} />
<RouteWithErrorBoundary path={`${match.path}/assets`} component={DamPage} />
Expand Down
4 changes: 4 additions & 0 deletions demo/admin/src/common/MasterMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ export const MasterMenu: React.FC = () => {
primary={intl.formatMessage({ id: "menu.newsletter.contacts", defaultMessage: "Contacts" })}
to={`${match.url}/newsletter/contacts`}
/>
<MenuItemRouterLink
primary={intl.formatMessage({ id: "menu.newsletter.targetGroups", defaultMessage: "Target groups" })}
to={`${match.url}/newsletter/target-groups`}
/>
</MenuCollapsibleItem>
<MenuCollapsibleItem primary={intl.formatMessage({ id: "menu.structuredContent", defaultMessage: "Structured content" })} icon={<Data />}>
<MenuItemRouterLink
Expand Down
7 changes: 6 additions & 1 deletion demo/api/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ type Mutation {
sendEmailCampaignNow(id: ID!): Boolean!
sendEmailCampaignToTestEmails(id: ID!, data: SendTestEmailCampaignArgs!): Boolean!
createTargetGroup(scope: EmailCampaignContentScopeInput!, input: TargetGroupInput!): TargetGroup!
updateTargetGroup(id: ID!, input: TargetGroupInput!, lastUpdatedAt: DateTime): TargetGroup!
updateTargetGroup(id: ID!, input: TargetGroupUpdateInput!, lastUpdatedAt: DateTime): TargetGroup!
deleteTargetGroup(id: ID!): Boolean!
}

Expand Down Expand Up @@ -863,3 +863,8 @@ input TargetGroupInput {
title: String!
filters: BrevoContactFilterAttributesInput
}

input TargetGroupUpdateInput {
title: String
filters: BrevoContactFilterAttributesInput
}
1 change: 1 addition & 0 deletions packages/admin/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { createBrevoContactsPage } from "./brevoContacts/BrevoContactsPage";
export { createTargetGroupsPage } from "./targetGroups/TargetGroupsPage";
48 changes: 48 additions & 0 deletions packages/admin/src/targetGroups/TargetGroupForm.gql.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { gql } from "@apollo/client";

export const targetGroupFormFragment = gql`
fragment TargetGroupForm on TargetGroup {
title
}
`;

export const targetGroupFormQuery = gql`
query TargetGroupForm($id: ID!) {
targetGroup(id: $id) {
id
updatedAt
...TargetGroupForm
}
}
${targetGroupFormFragment}
`;

export const targetGroupFormCheckForChangesQuery = gql`
query TargetGroupFormCheckForChanges($id: ID!) {
targetGroup(id: $id) {
updatedAt
}
}
`;

export const createTargetGroupMutation = gql`
mutation CreateTargetGroup($scope: EmailCampaignContentScopeInput!, $input: TargetGroupInput!) {
createTargetGroup(scope: $scope, input: $input) {
id
updatedAt
...TargetGroupForm
}
}
${targetGroupFormFragment}
`;

export const updateTargetGroupMutation = gql`
mutation UpdateTargetGroup($id: ID!, $input: TargetGroupUpdateInput!, $lastUpdatedAt: DateTime) {
updateTargetGroup(id: $id, input: $input, lastUpdatedAt: $lastUpdatedAt) {
id
updatedAt
...TargetGroupForm
}
}
${targetGroupFormFragment}
`;
156 changes: 156 additions & 0 deletions packages/admin/src/targetGroups/TargetGroupForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import { useApolloClient, useQuery } from "@apollo/client";
import {
Field,
FinalForm,
FinalFormInput,
FinalFormSaveSplitButton,
FinalFormSubmitEvent,
Loading,
MainContent,
Toolbar,
ToolbarActions,
ToolbarFillSpace,
ToolbarItem,
ToolbarTitleItem,
useFormApiRef,
useStackApi,
useStackSwitchApi,
} from "@comet/admin";
import { ArrowLeft } from "@comet/admin-icons";
import { ContentScopeInterface, EditPageLayout, queryUpdatedAt, resolveHasSaveConflict, useFormSaveConflict } from "@comet/cms-admin";
import { IconButton } from "@mui/material";
import { FormApi } from "final-form";
import React from "react";
import { FormattedMessage } from "react-intl";

import { createTargetGroupMutation, targetGroupFormQuery, updateTargetGroupMutation } from "./TargetGroupForm.gql";
import {
GQLCreateTargetGroupMutation,
GQLCreateTargetGroupMutationVariables,
GQLTargetGroupFormFragment,
GQLTargetGroupFormQuery,
GQLTargetGroupFormQueryVariables,
GQLUpdateTargetGroupMutation,
GQLUpdateTargetGroupMutationVariables,
} from "./TargetGroupForm.gql.generated";

type FormValues = GQLTargetGroupFormFragment;

interface FormProps {
id?: string;
scope: ContentScopeInterface;
}

export function TargetGroupForm({ id, scope }: FormProps): React.ReactElement {
const stackApi = useStackApi();
const client = useApolloClient();
const mode = id ? "edit" : "add";
const formApiRef = useFormApiRef<FormValues>();
const stackSwitchApi = useStackSwitchApi();

const { data, error, loading, refetch } = useQuery<GQLTargetGroupFormQuery, GQLTargetGroupFormQueryVariables>(
targetGroupFormQuery,
id ? { variables: { id } } : { skip: true },
);

const initialValues = React.useMemo<Partial<FormValues>>(
() =>
data?.targetGroup
? {
title: data.targetGroup.title,
}
: {},
[data],
);

const saveConflict = useFormSaveConflict({
checkConflict: async () => {
const updatedAt = await queryUpdatedAt(client, "targetGroup", id);
return resolveHasSaveConflict(data?.targetGroup.updatedAt, updatedAt);
},
formApiRef,
loadLatestVersion: async () => {
await refetch();
},
});

const handleSubmit = async (state: FormValues, form: FormApi<FormValues>, event: FinalFormSubmitEvent) => {
if (await saveConflict.checkForConflicts()) {
throw new Error("Conflicts detected");
}

const output = {
...state,
};

if (mode === "edit") {
if (!id) {
throw new Error("Missing id in edit mode");
}
await client.mutate<GQLUpdateTargetGroupMutation, GQLUpdateTargetGroupMutationVariables>({
mutation: updateTargetGroupMutation,
variables: { id, input: output, lastUpdatedAt: data?.targetGroup?.updatedAt },
});
} else {
const { data: mutationResponse } = await client.mutate<GQLCreateTargetGroupMutation, GQLCreateTargetGroupMutationVariables>({
mutation: createTargetGroupMutation,
variables: { scope, input: output },
});
if (!event.navigatingBack) {
const id = mutationResponse?.createTargetGroup.id;
if (id) {
setTimeout(() => {
stackSwitchApi.activatePage("edit", id);
});
}
}
}
};

if (error) throw error;

if (loading) {
return <Loading behavior="fillPageHeight" />;
}

return (
<FinalForm<FormValues>
apiRef={formApiRef}
onSubmit={handleSubmit}
mode={mode}
initialValues={initialValues}
onAfterSubmit={(values, form) => {
//don't go back automatically
}}
>
{({ values }) => (
<EditPageLayout>
{saveConflict.dialogs}
<Toolbar>
<ToolbarItem>
<IconButton onClick={stackApi?.goBack}>
<ArrowLeft />
</IconButton>
</ToolbarItem>
<ToolbarTitleItem>
<FormattedMessage id="cometBrevoModule.targetGroups.TargetGroup" defaultMessage="Target group" />
</ToolbarTitleItem>
<ToolbarFillSpace />
<ToolbarActions>
<FinalFormSaveSplitButton hasConflict={saveConflict.hasConflict} />
</ToolbarActions>
</Toolbar>
<MainContent>
<Field
required
fullWidth
name="title"
component={FinalFormInput}
label={<FormattedMessage id="cometBrevoModule.targetGroup.title" defaultMessage="Title" />}
/>
</MainContent>
</EditPageLayout>
)}
</FinalForm>
);
}
Loading

0 comments on commit 3089d40

Please sign in to comment.