Skip to content

Commit

Permalink
Merge pull request #30 from vivid-planet/add-dynamic-fields-to-target…
Browse files Browse the repository at this point in the history
…-group-form

COM-271: Add dynamic fields to target group form
  • Loading branch information
RainbowBunchie authored Jan 30, 2024
2 parents 3089d40 + 8cdbcf4 commit 4339960
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 39 deletions.
10 changes: 8 additions & 2 deletions demo/admin/src/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useIntl } from "react-intl";
import { RouteComponentProps } from "react-router";
import { Redirect, Route, Switch } from "react-router-dom";

import { additionalFormConfig } from "./common/brevoModuleConfig/targetGroupFormConfig";
import { ContentScopeIndicatorContent, ContentScopeIndicatorDomain, ContentScopeIndicatorLanguage } from "./common/ContentScopeIndicatorStyles";
import { ContentScopeProvider } from "./common/ContentScopeProvider";
import { MasterHeader } from "./common/MasterHeader";
Expand All @@ -19,18 +20,23 @@ 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();
const brevoContactConfig = getBrevoContactConfig(intl);

const BrevoContactsPage = createBrevoContactsPage({
scopeParts: ["domain", "language"],
additionalAttributesFragment: brevoContactConfig.additionalAttributesFragment,
additionalGridFields: brevoContactConfig.additionalGridFields,
});

const TargetGroupsPage = createTargetGroupsPage({
scopeParts: ["domain", "language"],
additionalFormFields: additionalFormConfig.additionalFormFields,
nodeFragment: additionalFormConfig.nodeFragment,
input2State: additionalFormConfig.input2State,
});

return (
<ContentScopeProvider>
{({ match }) => (
Expand Down
54 changes: 54 additions & 0 deletions demo/admin/src/common/brevoModuleConfig/targetGroupFormConfig.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { gql } from "@apollo/client";
import { Field, FinalFormSelect } from "@comet/admin";
import { MenuItem } from "@mui/material";
import { GQLBrevoContactSalutation } from "@src/graphql.generated";
import * as React from "react";
import { FormattedMessage } from "react-intl";

const salutationOptions: Array<{ label: React.ReactNode; value: GQLBrevoContactSalutation }> = [
{
label: <FormattedMessage id="targetGroup.filters.salutation.male." defaultMessage="Male" />,
value: "MALE",
},
{
label: <FormattedMessage id="targetGroup.filters.salutation.female." defaultMessage="Female" />,
value: "FEMALE",
},
];

export const additionalPageTreeNodeFieldsFragment = {
fragment: gql`
fragment TargetGroupFilters on TargetGroup {
filters {
SALUTATION
}
}
`,
name: "TargetGroupFilters",
};

export const additionalFormConfig = {
input2State: (values?: { filters: { SALUTATION: Array<GQLBrevoContactSalutation> } }) => {
return {
filters: {
SALUTATION: values?.filters?.SALUTATION ?? [],
},
};
},
nodeFragment: additionalPageTreeNodeFieldsFragment,
additionalFormFields: (
<>
<Field label={<FormattedMessage id="targetGroup.fields.salutation" defaultMessage="Salutation" />} name="filters.SALUTATION" fullWidth>
{(props) => (
<FinalFormSelect {...props} fullWidth multiple clearable>
{salutationOptions.map((option) => (
<MenuItem value={option.value} key={option.value}>
{option.label}
</MenuItem>
))}
</FinalFormSelect>
)}
</Field>
</>
),
};
2 changes: 1 addition & 1 deletion packages/admin/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"extends": "@comet/eslint-config/react",
"ignorePatterns": ["src/*.generated.ts", "lib/**"]
"ignorePatterns": ["**/*.generated.ts", "lib/**"]
}
3 changes: 1 addition & 2 deletions packages/admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
"rimraf": "^3.0.2",
"typescript": "^4.0.0"
},

"peerDependencies": {
"@apollo/client": "^3.2.5",
"@comet/admin": "^5.3.0",
Expand Down Expand Up @@ -95,4 +94,4 @@
"access": "public",
"registry": "https://registry.npmjs.org"
}
}
}
14 changes: 4 additions & 10 deletions packages/admin/src/targetGroups/TargetGroupForm.gql.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { gql } from "@apollo/client";
import { DocumentNode, gql } from "@apollo/client";

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

export const targetGroupFormQuery = gql`
export const targetGroupFormQuery = (targetGroupFormFragment: DocumentNode) => gql`
query TargetGroupForm($id: ID!) {
targetGroup(id: $id) {
id
Expand All @@ -25,7 +19,7 @@ export const targetGroupFormCheckForChangesQuery = gql`
}
`;

export const createTargetGroupMutation = gql`
export const createTargetGroupMutation = (targetGroupFormFragment: DocumentNode) => gql`
mutation CreateTargetGroup($scope: EmailCampaignContentScopeInput!, $input: TargetGroupInput!) {
createTargetGroup(scope: $scope, input: $input) {
id
Expand All @@ -36,7 +30,7 @@ export const createTargetGroupMutation = gql`
${targetGroupFormFragment}
`;

export const updateTargetGroupMutation = gql`
export const updateTargetGroupMutation = (targetGroupFormFragment: DocumentNode) => gql`
mutation UpdateTargetGroup($id: ID!, $input: TargetGroupUpdateInput!, $lastUpdatedAt: DateTime) {
updateTargetGroup(id: $id, input: $input, lastUpdatedAt: $lastUpdatedAt) {
id
Expand Down
65 changes: 45 additions & 20 deletions packages/admin/src/targetGroups/TargetGroupForm.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useApolloClient, useQuery } from "@apollo/client";
import { DocumentNode, gql, useApolloClient, useQuery } from "@apollo/client";
import {
Field,
FinalForm,
FinalFormInput,
FinalFormSaveSplitButton,
FinalFormSubmitEvent,
FormSection,
Loading,
MainContent,
Toolbar,
Expand All @@ -18,7 +19,7 @@ import {
} 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 { Card, IconButton } from "@mui/material";
import { FormApi } from "final-form";
import React from "react";
import { FormattedMessage } from "react-intl";
Expand All @@ -27,41 +28,54 @@ import { createTargetGroupMutation, targetGroupFormQuery, updateTargetGroupMutat
import {
GQLCreateTargetGroupMutation,
GQLCreateTargetGroupMutationVariables,
GQLTargetGroupFormFragment,
GQLTargetGroupFormQuery,
GQLTargetGroupFormQueryVariables,
GQLUpdateTargetGroupMutation,
GQLUpdateTargetGroupMutationVariables,
} from "./TargetGroupForm.gql.generated";

type FormValues = GQLTargetGroupFormFragment;
export interface EditTargetGroupFinalFormValues {
title: string;
[key: string]: unknown;
}

interface FormProps {
id?: string;
scope: ContentScopeInterface;
additionalFormFields?: React.ReactNode;
nodeFragment?: { name: string; fragment: DocumentNode };
input2State?: (values?: EditTargetGroupFinalFormValues) => EditTargetGroupFinalFormValues;
}

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

const targetGroupFormFragment = gql`
fragment TargetGroupForm on TargetGroup {
title
${nodeFragment ? "...".concat(nodeFragment?.name) : ""}
}
${nodeFragment?.fragment ?? ""}
`;

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

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

if (input2State) {
additionalInitialValues = input2State(data?.targetGroup);
}

return data?.targetGroup ? { title: data.targetGroup.title, ...additionalInitialValues } : additionalInitialValues;
}, [data?.targetGroup, input2State]);

const saveConflict = useFormSaveConflict({
checkConflict: async () => {
Expand All @@ -74,7 +88,11 @@ export function TargetGroupForm({ id, scope }: FormProps): React.ReactElement {
},
});

const handleSubmit = async (state: FormValues, form: FormApi<FormValues>, event: FinalFormSubmitEvent) => {
const handleSubmit = async (
state: EditTargetGroupFinalFormValues,
form: FormApi<EditTargetGroupFinalFormValues>,
event: FinalFormSubmitEvent,
) => {
if (await saveConflict.checkForConflicts()) {
throw new Error("Conflicts detected");
}
Expand All @@ -88,12 +106,12 @@ export function TargetGroupForm({ id, scope }: FormProps): React.ReactElement {
throw new Error("Missing id in edit mode");
}
await client.mutate<GQLUpdateTargetGroupMutation, GQLUpdateTargetGroupMutationVariables>({
mutation: updateTargetGroupMutation,
mutation: updateTargetGroupMutation(targetGroupFormFragment),
variables: { id, input: output, lastUpdatedAt: data?.targetGroup?.updatedAt },
});
} else {
const { data: mutationResponse } = await client.mutate<GQLCreateTargetGroupMutation, GQLCreateTargetGroupMutationVariables>({
mutation: createTargetGroupMutation,
mutation: createTargetGroupMutation(targetGroupFormFragment),
variables: { scope, input: output },
});
if (!event.navigatingBack) {
Expand All @@ -114,7 +132,7 @@ export function TargetGroupForm({ id, scope }: FormProps): React.ReactElement {
}

return (
<FinalForm<FormValues>
<FinalForm<EditTargetGroupFinalFormValues>
apiRef={formApiRef}
onSubmit={handleSubmit}
mode={mode}
Expand Down Expand Up @@ -148,6 +166,13 @@ export function TargetGroupForm({ id, scope }: FormProps): React.ReactElement {
component={FinalFormInput}
label={<FormattedMessage id="cometBrevoModule.targetGroup.title" defaultMessage="Title" />}
/>
{additionalFormFields && (
<Card sx={{ padding: 4 }}>
<FormSection title={<FormattedMessage id="cometBrevoModule.targetGroup.filters" defaultMessage="Filters" />}>
{additionalFormFields}
</FormSection>
</Card>
)}
</MainContent>
</EditPageLayout>
)}
Expand Down
26 changes: 22 additions & 4 deletions packages/admin/src/targetGroups/TargetGroupsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import { Stack, StackPage, StackSwitch } from "@comet/admin";
import { useContentScope } from "@comet/cms-admin";
import { DocumentNode } from "graphql";
import * as React from "react";
import { useIntl } from "react-intl";

import { TargetGroupForm } from "./TargetGroupForm";
import { EditTargetGroupFinalFormValues, TargetGroupForm } from "./TargetGroupForm";
import { TargetGroupsGrid } from "./TargetGroupsGrid";

interface CreateContactsPageOptions {
scopeParts: string[];
additionalFormFields?: React.ReactNode;
nodeFragment?: { name: string; fragment: DocumentNode };
input2State?: (values?: EditTargetGroupFinalFormValues) => EditTargetGroupFinalFormValues;
valuesToOutput?: (values: EditTargetGroupFinalFormValues) => EditTargetGroupFinalFormValues;
}

export function createTargetGroupsPage({ scopeParts }: CreateContactsPageOptions) {
export function createTargetGroupsPage({ scopeParts, additionalFormFields, nodeFragment, input2State }: CreateContactsPageOptions) {
function TargetGroupsPage(): JSX.Element {
const { scope: completeScope } = useContentScope();
const intl = useIntl();
Expand All @@ -30,13 +35,26 @@ export function createTargetGroupsPage({ scopeParts }: CreateContactsPageOptions
name="edit"
title={intl.formatMessage({ id: "cometBrevoModule.targetGroups.editTargetGroup", defaultMessage: "Edit target group" })}
>
{(selectedId) => <TargetGroupForm id={selectedId} scope={scope} />}
{(selectedId) => (
<TargetGroupForm
id={selectedId}
scope={scope}
additionalFormFields={additionalFormFields}
nodeFragment={nodeFragment}
input2State={input2State}
/>
)}
</StackPage>
<StackPage
name="add"
title={intl.formatMessage({ id: "cometBrevoModule.targetGroups.addTargetGroup", defaultMessage: "Add target group" })}
>
<TargetGroupForm scope={scope} />
<TargetGroupForm
scope={scope}
additionalFormFields={additionalFormFields}
nodeFragment={nodeFragment}
input2State={input2State}
/>
</StackPage>
</StackSwitch>
</Stack>
Expand Down

0 comments on commit 4339960

Please sign in to comment.