Skip to content

Commit

Permalink
display the initial document as expected
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-burel committed Jun 11, 2021
1 parent 98b23f1 commit fce4ae1
Show file tree
Hide file tree
Showing 16 changed files with 269 additions and 128 deletions.
2 changes: 2 additions & 0 deletions packages/graphql/templates/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ updateMovie(input: UpdateMovieInput) : MovieOutput
*/
export const updateMutationType = (typeName) => `update${typeName}`;
export const updateOperationName = (model: VulcanGraphqlModel) =>
updateMutationType(model.graphql.typeName);
export const updateMutationTemplate = ({ typeName }) =>
`${updateMutationType(typeName)}(
input: ${updateInputType(typeName)},
Expand Down
14 changes: 12 additions & 2 deletions packages/graphql/typings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,20 +128,30 @@ export interface ApolloVariables<TInput> {
}

// Mutation/Hooks typings
export interface CreateInput<TModel = any> {
interface CommonInput {
contextName?: string;
}
export interface CreateInput<TModel = any> extends CommonInput {
data: TModel;
}
export interface CreateVariables<TModel = any> {
input: CreateInput<TModel>;
}
export interface UpdateInput<TModel> {
export interface UpdateInput<TModel> extends CommonInput {
data: TModel;
id?: string;
}
export interface UpdateVariables<TModel = any> {
input: UpdateInput<TModel>;
}

export interface DeleteInput extends CommonInput {
id: string;
}
export interface DeleteVariables {
input: DeleteInput;
}

// Filtering and selectors
type VulcanSelectorSortOption = "asc" | "desc";

Expand Down
7 changes: 1 addition & 6 deletions packages/react-hooks/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const buildDeleteQuery = ({ typeName, fragmentName, fragment }) =>
`;

import { multiQueryUpdater, ComputeNewDataFunc } from "./multiQueryUpdater";
import { DeleteVariables } from "@vulcanjs/graphql";

/**
* Compute new list for removed elements
Expand All @@ -63,12 +64,6 @@ const multiQueryUpdaterAfterDelete = multiQueryUpdater(
computeNewDataAfterDelete
);

interface DeleteInput {
id: string;
}
interface DeleteVariables {
input: DeleteInput;
}
interface UseDeleteOptions
extends VulcanMutationHookOptions,
Partial<DeleteVariables> {}
Expand Down
2 changes: 1 addition & 1 deletion packages/react-hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ export type { UseSingleOptions } from "./single";
export { useMulti } from "./multi";
export { useCreate, buildCreateQuery } from "./create";
export { useDelete } from "./delete";
export { useUpdate } from "./update";
export { useUpdate, buildUpdateQuery } from "./update";
export { useUpsert } from "./upsert";
38 changes: 18 additions & 20 deletions packages/react-hooks/multi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,24 +124,23 @@ export const buildMultiQueryOptions = <TModel, TData>(
* Query updater after a fetch more
* @param resolverName
*/
export const fetchMoreUpdateQuery = (resolverName: string) => (
previousResults,
{ fetchMoreResult }
) => {
// no more post to fetch
if (!fetchMoreResult[resolverName]?.results?.length) {
return previousResults;
}
const newResults = {
...previousResults,
[resolverName]: { ...previousResults[resolverName] },
export const fetchMoreUpdateQuery =
(resolverName: string) =>
(previousResults, { fetchMoreResult }) => {
// no more post to fetch
if (!fetchMoreResult[resolverName]?.results?.length) {
return previousResults;
}
const newResults = {
...previousResults,
[resolverName]: { ...previousResults[resolverName] },
};
newResults[resolverName].results = [
...previousResults[resolverName].results,
...fetchMoreResult[resolverName].results,
];
return newResults;
};
newResults[resolverName].results = [
...previousResults[resolverName].results,
...fetchMoreResult[resolverName].results,
];
return newResults;
};

const buildMultiResult = <TModel, TData, TVariables>(
options: UseMultiOptions<TModel, TData, TVariables>,
Expand All @@ -155,9 +154,8 @@ const buildMultiResult = <TModel, TData, TVariables>(
const graphQLErrors = get(queryResult, "error.networkError.result.errors");
const { refetch, networkStatus, error, fetchMore, data } = queryResult;
// Note: Scalar types like Dates are NOT converted. It should be done at the UI level.
const documents = data && data[resolverName] && data[resolverName].results;
const totalCount =
data && data[resolverName] && data[resolverName].totalCount;
const documents = data?.[resolverName]?.results;
const totalCount = data?.[resolverName]?.data[resolverName]?.totalCount;
// see https://github.com/apollographql/apollo-client/blob/master/packages/apollo-client/src/core/networkStatus.ts
const loadingInitial = networkStatus === 1;
const loadingMore = networkStatus === 3 || networkStatus === 2;
Expand Down
4 changes: 2 additions & 2 deletions packages/react-hooks/single.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ const buildSingleResult = <TModel = any, TData = any>(
const result = {
...queryResult,
// Note: Scalar types like Dates are NOT converted. It should be done at the UI level.
document: data && data[resolverName] && data[resolverName].result,
document: data?.[resolverName]?.result,
fragmentName,
fragment,
};
Expand Down Expand Up @@ -140,7 +140,7 @@ export const useSingle = <TModel = any, TData = any>(
extraQueries,
} = options;

const { typeName, singleResolverName: resolverName } = model.graphql;
const { singleResolverName: resolverName } = model.graphql;

const query = buildSingleQuery({
model,
Expand Down
33 changes: 26 additions & 7 deletions packages/react-hooks/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,17 @@

import { useMutation, MutationResult, gql, FetchResult } from "@apollo/client";

import { updateClientTemplate } from "@vulcanjs/graphql";
import {
Fragment,
getModelFragment,
updateClientTemplate,
} from "@vulcanjs/graphql";

import { multiQueryUpdater, ComputeNewDataFunc } from "./multiQueryUpdater";
// import { computeQueryVariables } from "./variables";
import { computeNewDataAfterCreate } from "./create";
import { VulcanMutationHookOptions } from "./typings";
import { UpdateVariables } from "@vulcanjs/graphql"; // TODO: import client code only
import { UpdateVariables, VulcanGraphqlModel } from "@vulcanjs/graphql"; // TODO: import client code only

// We can reuse the same function to compute the new list after an element update
const computeNewDataAfterUpdate: ComputeNewDataFunc = computeNewDataAfterCreate;
Expand All @@ -44,11 +48,26 @@ const multiQueryUpdaterAfterUpdate = multiQueryUpdater(
computeNewDataAfterUpdate
);

export const buildUpdateQuery = ({ typeName, fragmentName, fragment }) =>
gql`
${updateClientTemplate({ typeName, fragmentName })}
${fragment}
export const buildUpdateQuery = ({
model,
fragmentName,
fragment,
}: {
model: VulcanGraphqlModel;
fragmentName?: string;
fragment?: Fragment;
}) => {
const { typeName } = model.graphql;
const { finalFragment, finalFragmentName } = getModelFragment({
model,
fragment,
fragmentName,
});
return gql`
${updateClientTemplate({ typeName, fragmentName: finalFragmentName })}
${finalFragment}
`;
};

// Options of the hook
interface UseUpdateOptions<TModel = any>
Expand Down Expand Up @@ -82,7 +101,7 @@ export const useUpdate = <TModel = any>(

const { typeName } = model.graphql;

const query = buildUpdateQuery({ typeName, fragmentName, fragment });
const query = buildUpdateQuery({ model, fragmentName, fragment });

const resolverName = `update${typeName}`;

Expand Down
54 changes: 28 additions & 26 deletions packages/react-ui/components/form/Form/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,12 @@ import { useWarnOnUnsaved } from "../useWarnOnUnsaved";
import { useVulcanComponents } from "../VulcanComponents/Consumer";

import type { FormType } from "../typings";
import { CreateDocumentResult, FormProps, FormState } from "./typings";
import {
CreateDocumentResult,
FormProps,
FormState,
UpdateDocumentResult,
} from "./typings";
import { MutationResult } from "@apollo/client";

// props that should trigger a form reset
Expand Down Expand Up @@ -304,9 +309,10 @@ const getData = (
};

export const Form = (props: FormProps) => {
const { initCallback, createDocument, createDocumentMeta } = props;
const { initCallback, createDocument, updateDocument, deleteDocument } =
props;
const initialState = getInitialStateFromProps(props);
const { schema, originalSchema, flatSchema } = initialState;
const { schema, originalSchema, flatSchema, initialDocument } = initialState;
const isFirstRender = useRef(true);
useEffect(() => {
if (isFirstRender.current) {
Expand Down Expand Up @@ -467,11 +473,12 @@ export const Form = (props: FormProps) => {
}
}*/

const [currentDocument, setCurrentDocument] = useState<{
title?: string;
_id?: string;
name?: string;
}>({});
const [currentDocument, setCurrentDocument] =
useState<{
title?: string;
_id?: string;
name?: string;
}>(initialDocument);

/*
Expand Down Expand Up @@ -536,7 +543,6 @@ export const Form = (props: FormProps) => {
}
};

const [initialDocument, setInitialDocument] = useState<Object>({});
const [disabled, setDisabled] = useState<boolean>(false); // TODO
const [success, setSuccess] = useState<boolean>(false); // TODO
/**
Expand Down Expand Up @@ -572,7 +578,7 @@ export const Form = (props: FormProps) => {
setCurrentValues({});
setDeletedValues([]);
setCurrentDocument(document || initialDocument);
setInitialDocument(document || initialDocument);
// setInitialDocument(document || initialDocument);
setDisabled(false);
};

Expand All @@ -583,7 +589,7 @@ export const Form = (props: FormProps) => {
};

const editMutationSuccessCallback = function <TModel = Object>(
result: CreateDocumentResult<TModel>
result: UpdateDocumentResult<TModel>
) {
mutationSuccessCallback(result, "edit");
};
Expand All @@ -598,7 +604,9 @@ export const Form = (props: FormProps) => {
setDisabled(false);
setSuccess(true);
// for new mutation, run refetch function if it exists
if (mutationType === "new" && props.refetch) props.refetch();
// TODO: the create mutation should already return the freshest value, do we really need that?
// instead we might want to update currentResult with the result of the creation
if (mutationType === "new") refetchForm();
let { document } = result;

// call the clear form method (i.e. trigger setState) only if the form has not been unmounted
Expand Down Expand Up @@ -697,8 +705,6 @@ export const Form = (props: FormProps) => {
contextName,
},
});
// in new versions of Apollo Client errors are no longer thrown/caught
// but can instead be provided as props by the useMutation hook
if (result.errors?.length) {
// TODO: previously got from meta, we could have more than 1 error
mutationErrorCallback(document, result.errors[0]);
Expand All @@ -712,19 +718,16 @@ export const Form = (props: FormProps) => {
// update document form
try {
const documentId = currentDocument._id;
const result = await props.updateDocument({
const result = await updateDocument({
input: {
id: documentId,
data,
contextName,
},
});
// TODO: ?? what is Meta?
const meta = props.updateDocumentMeta;
// in new versions of Apollo Client errors are no longer thrown/caught
// but can instead be provided as props by the useMutation hook
if (meta?.error) {
mutationErrorCallback(document, meta.error);
// TODO: handle more than 1 error
if (result.errors?.length) {
mutationErrorCallback(document, result.errors[0]);
} else {
editMutationSuccessCallback(result);
}
Expand All @@ -739,7 +742,7 @@ export const Form = (props: FormProps) => {
Delete document handler
*/
const deleteDocument = () => {
const deleteDocumentWithConfirm = () => {
const document = currentDocument;
const documentId = props.document._id;
const documentTitle = document.title || document.name || "";
Expand All @@ -750,13 +753,12 @@ export const Form = (props: FormProps) => {
);

if (window.confirm(deleteDocumentConfirm)) {
props
.deleteDocument({ input: { id: documentId } })
deleteDocument({ input: { id: documentId } })
.then((mutationResult) => {
// the mutation result looks like {data:{collectionRemove: null}} if succeeded
if (props.removeSuccessCallback)
props.removeSuccessCallback({ documentId, documentTitle });
if (props.refetch) props.refetch();
refetchForm();
})
.catch((error) => {
// eslint-disable-next-line no-console
Expand Down Expand Up @@ -792,7 +794,7 @@ export const Form = (props: FormProps) => {
formType,
},
{
deleteDocument,
deleteDocument: deleteDocumentWithConfirm,
}
);
const isChanged = isNotSameDocument(initialDocument, currentDocument);
Expand Down
Loading

0 comments on commit fce4ae1

Please sign in to comment.