diff --git a/backend/db_migrations/000021_duplicate-meal-name-input.down.sql b/backend/db_migrations/000021_duplicate-meal-name-input.down.sql new file mode 100644 index 00000000..da5e50a5 --- /dev/null +++ b/backend/db_migrations/000021_duplicate-meal-name-input.down.sql @@ -0,0 +1,28 @@ +revoke execute on function app.duplicate_meal_plan(bigint,bigint,text) from app_admin, app_meal_designer, app_user; +drop function if exists app.duplicate_meal_plan(bigint,bigint,text); --otherwise it creates two separate functions +comment on column app.meal_plan_entry.days is 'MONDAY: 0, TUESDAY: 1.., SUNDAY: 6'; +create or replace function app.duplicate_meal_plan(mealplan_id bigint, p_id bigint) returns app.meal_plan as $$ +declare +m app.meal_plan; +entry_ids bigint[]; +begin +--create a duplicate meal plan with a different meal plan id and person id p_id but the same contents +INSERT INTO app.meal_plan (name_en, name_fr, person_id, description_en, description_fr, tags) + SELECT name_en, name_fr, p_id as person_id, description_en, description_fr, tags FROM app.meal_plan WHERE id=mealplan_id +RETURNING * INTO m; +-- m = UPDATE app.meal_plan SET person_id=p_id WHERE id = m.id RETURNING *; + +--create duplicate of all meal plan entries associated with the meal_plan_id + +INSERT INTO app.meal_plan_entry (category, days, meal_plan_id, meal_id) +SELECT category, days, m.id AS meal_plan_id, meal_id FROM app.meal_plan_entry +WHERE meal_plan_id = mealplan_id; + +return m; + +end; + +$$ language plpgsql; + +comment on function app.duplicate_meal_plan(bigint, bigint) is 'Duplicate meal plan by meal designer or admin'; +GRANT execute on function app.duplicate_meal_plan(bigint, bigint) to app_admin, app_meal_designer; \ No newline at end of file diff --git a/backend/db_migrations/000021_duplicate-meal-name-input.up.sql b/backend/db_migrations/000021_duplicate-meal-name-input.up.sql new file mode 100644 index 00000000..2dec6aee --- /dev/null +++ b/backend/db_migrations/000021_duplicate-meal-name-input.up.sql @@ -0,0 +1,38 @@ + +comment on column app.meal_plan_entry.days is 'MONDAY: 0, TUESDAY: 1.., SUNDAY: 6'; +revoke execute on function app.duplicate_meal_plan(bigint,bigint) from app_admin, app_meal_designer, app_user; +drop function if exists app.duplicate_meal_plan(bigint,bigint); --otherwise it creates two separate functions +create or replace function app.duplicate_meal_plan(mealplan_id bigint, p_id bigint, dup_name_en text) returns app.meal_plan as $$ +declare +m app.meal_plan; +entry_ids bigint[]; +p app.person; +begin +p := app.current_user_person(app.current_person()); + +--create a duplicate meal plan with a different meal plan id and person id p_id but the same contents +IF (p.id = p_id and p.role='app_user') THEN + INSERT INTO app.meal_plan (name_en, name_fr, person_id, description_en, description_fr, tags) + SELECT dup_name_en as name_en, name_fr, p_id as person_id, description_en, description_fr, tags FROM app.meal_plan WHERE id=mealplan_id + RETURNING * INTO m; +ELSE + INSERT INTO app.meal_plan (name_en, name_fr, person_id, description_en, description_fr, tags) + SELECT dup_name_en as name_en, name_fr, null, description_en, description_fr, tags FROM app.meal_plan WHERE id=mealplan_id + RETURNING * INTO m; +END IF; +-- m = UPDATE app.meal_plan SET person_id=p_id WHERE id = m.id RETURNING *; + +--create duplicate of all meal plan entries associated with the meal_plan_id + +INSERT INTO app.meal_plan_entry (category, days, meal_plan_id, meal_id) +SELECT category, days, m.id AS meal_plan_id, meal_id FROM app.meal_plan_entry +WHERE meal_plan_id = mealplan_id; + +return m; + +end; + +$$ language plpgsql; + +comment on function app.duplicate_meal_plan(bigint, bigint,text) is 'Duplicate meal plan by meal designer, admin, or user'; +GRANT execute on function app.duplicate_meal_plan(bigint, bigint,text) to app_admin, app_meal_designer, app_user; \ No newline at end of file diff --git a/mealplanner-ui/src/pages/MealPlans/DuplicateMealPlan.tsx b/mealplanner-ui/src/pages/MealPlans/DuplicateMealPlan.tsx index e20ae864..25ad7ebd 100644 --- a/mealplanner-ui/src/pages/MealPlans/DuplicateMealPlan.tsx +++ b/mealplanner-ui/src/pages/MealPlans/DuplicateMealPlan.tsx @@ -3,8 +3,8 @@ import { commitMutation } from "relay-runtime"; import environment from "../../relay/environment"; const duplicateMealPlanGQL = graphql` -mutation DuplicateMealPlanMutation($connections: [ID!]!, $mealPlanId: BigInt!, $personId:BigInt!) { - duplicateMealPlan(input: {mealplanId: $mealPlanId, personId: $personId}) { +mutation DuplicateMealPlanMutation($connections: [ID!]!, $mealPlanId: BigInt!, $personId:BigInt!, $duplicateNameEn:String!) { + duplicateMealPlan(input: {mealplanId: $mealPlanId, pId: $personId, dupNameEn: $duplicateNameEn}) { mealPlanEdge @prependEdge(connections: $connections) { cursor node { @@ -34,13 +34,14 @@ mutation DuplicateMealPlanMutation($connections: [ID!]!, $mealPlanId: BigInt!, $ `; -export const duplicateMealPlan = (connection: string, id:string, pId:string) => { +export const duplicateMealPlan = (connection: string, id:string, pId:string, dupNameEn:string) => { commitMutation(environment, { mutation: duplicateMealPlanGQL, variables: { connections: [connection], mealPlanId: id.toString(), personId: pId.toString(), + duplicateNameEn: dupNameEn.toString(), }, onCompleted(response, errors) { console.log(response); diff --git a/mealplanner-ui/src/pages/MealPlans/MealPlanCard.tsx b/mealplanner-ui/src/pages/MealPlans/MealPlanCard.tsx index 658b91fe..d7401403 100644 --- a/mealplanner-ui/src/pages/MealPlans/MealPlanCard.tsx +++ b/mealplanner-ui/src/pages/MealPlans/MealPlanCard.tsx @@ -151,7 +151,7 @@ export const MealPlanCard = (props: MealPlanCardProps) => { aria-label="duplicate" onClick={(e) => { e.stopPropagation(); - duplicateMealPlan(connection, mealplan.rowId,getCurrentPerson().personID); + duplicateMealPlan(connection, mealplan.rowId,getCurrentPerson().personID, mealplan.nameEn.concat(" copy")); }} sx={{ "& :hover": { color: theme.palette.primary.main } }} > diff --git a/mealplanner-ui/src/pages/MealPlans/__generated__/DuplicateMealPlanMutation.graphql.ts b/mealplanner-ui/src/pages/MealPlans/__generated__/DuplicateMealPlanMutation.graphql.ts index fdccb8a5..5b489e5e 100644 --- a/mealplanner-ui/src/pages/MealPlans/__generated__/DuplicateMealPlanMutation.graphql.ts +++ b/mealplanner-ui/src/pages/MealPlans/__generated__/DuplicateMealPlanMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<442ec150748f0e90497d04ffab81182c>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -12,6 +12,8 @@ import { ConcreteRequest, Mutation } from 'relay-runtime'; export type DuplicateMealPlanMutation$variables = { connections: ReadonlyArray; mealPlanId: any; + personId: any; + duplicateNameEn: string; }; export type DuplicateMealPlanMutation$data = { readonly duplicateMealPlan: { @@ -22,6 +24,7 @@ export type DuplicateMealPlanMutation$data = { readonly rowId: any; readonly nameEn: string; readonly nameFr: string | null; + readonly personId: any | null; readonly descriptionEn: string | null; readonly descriptionFr: string | null; readonly person: { @@ -46,95 +49,120 @@ export type DuplicateMealPlanMutation = { }; const node: ConcreteRequest = (function(){ -var v0 = [ - { - "defaultValue": null, - "kind": "LocalArgument", - "name": "connections" - }, - { - "defaultValue": null, - "kind": "LocalArgument", - "name": "mealPlanId" - } -], -v1 = [ +var v0 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "connections" +}, +v1 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "duplicateNameEn" +}, +v2 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "mealPlanId" +}, +v3 = { + "defaultValue": null, + "kind": "LocalArgument", + "name": "personId" +}, +v4 = [ { "fields": [ + { + "kind": "Variable", + "name": "dupNameEn", + "variableName": "duplicateNameEn" + }, { "kind": "Variable", "name": "mealplanId", "variableName": "mealPlanId" + }, + { + "kind": "Variable", + "name": "pId", + "variableName": "personId" } ], "kind": "ObjectValue", "name": "input" } ], -v2 = { +v5 = { "alias": null, "args": null, "kind": "ScalarField", "name": "cursor", "storageKey": null }, -v3 = { +v6 = { "alias": null, "args": null, "kind": "ScalarField", "name": "id", "storageKey": null }, -v4 = { +v7 = { "alias": null, "args": null, "kind": "ScalarField", "name": "rowId", "storageKey": null }, -v5 = { +v8 = { "alias": null, "args": null, "kind": "ScalarField", "name": "nameEn", "storageKey": null }, -v6 = { +v9 = { "alias": null, "args": null, "kind": "ScalarField", "name": "nameFr", "storageKey": null }, -v7 = { +v10 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "personId", + "storageKey": null +}, +v11 = { "alias": null, "args": null, "kind": "ScalarField", "name": "descriptionEn", "storageKey": null }, -v8 = { +v12 = { "alias": null, "args": null, "kind": "ScalarField", "name": "descriptionFr", "storageKey": null }, -v9 = { +v13 = { "alias": null, "args": null, "kind": "ScalarField", "name": "fullName", "storageKey": null }, -v10 = { +v14 = { "alias": null, "args": null, "kind": "ScalarField", "name": "tags", "storageKey": null }, -v11 = { +v15 = { "alias": null, "args": null, "concreteType": "Meal", @@ -142,7 +170,7 @@ v11 = { "name": "meal", "plural": false, "selections": [ - (v3/*: any*/), + (v6/*: any*/), { "alias": null, "args": null, @@ -155,14 +183,19 @@ v11 = { }; return { "fragment": { - "argumentDefinitions": (v0/*: any*/), + "argumentDefinitions": [ + (v0/*: any*/), + (v1/*: any*/), + (v2/*: any*/), + (v3/*: any*/) + ], "kind": "Fragment", "metadata": null, "name": "DuplicateMealPlanMutation", "selections": [ { "alias": null, - "args": (v1/*: any*/), + "args": (v4/*: any*/), "concreteType": "DuplicateMealPlanPayload", "kind": "LinkedField", "name": "duplicateMealPlan", @@ -176,7 +209,7 @@ return { "name": "mealPlanEdge", "plural": false, "selections": [ - (v2/*: any*/), + (v5/*: any*/), { "alias": null, "args": null, @@ -185,12 +218,13 @@ return { "name": "node", "plural": false, "selections": [ - (v3/*: any*/), - (v4/*: any*/), - (v5/*: any*/), (v6/*: any*/), (v7/*: any*/), (v8/*: any*/), + (v9/*: any*/), + (v10/*: any*/), + (v11/*: any*/), + (v12/*: any*/), { "alias": null, "args": null, @@ -199,11 +233,11 @@ return { "name": "person", "plural": false, "selections": [ - (v9/*: any*/) + (v13/*: any*/) ], "storageKey": null }, - (v10/*: any*/), + (v14/*: any*/), { "alias": null, "args": null, @@ -220,7 +254,7 @@ return { "name": "nodes", "plural": true, "selections": [ - (v11/*: any*/) + (v15/*: any*/) ], "storageKey": null } @@ -242,13 +276,18 @@ return { }, "kind": "Request", "operation": { - "argumentDefinitions": (v0/*: any*/), + "argumentDefinitions": [ + (v0/*: any*/), + (v2/*: any*/), + (v3/*: any*/), + (v1/*: any*/) + ], "kind": "Operation", "name": "DuplicateMealPlanMutation", "selections": [ { "alias": null, - "args": (v1/*: any*/), + "args": (v4/*: any*/), "concreteType": "DuplicateMealPlanPayload", "kind": "LinkedField", "name": "duplicateMealPlan", @@ -262,7 +301,7 @@ return { "name": "mealPlanEdge", "plural": false, "selections": [ - (v2/*: any*/), + (v5/*: any*/), { "alias": null, "args": null, @@ -271,12 +310,13 @@ return { "name": "node", "plural": false, "selections": [ - (v3/*: any*/), - (v4/*: any*/), - (v5/*: any*/), (v6/*: any*/), (v7/*: any*/), (v8/*: any*/), + (v9/*: any*/), + (v10/*: any*/), + (v11/*: any*/), + (v12/*: any*/), { "alias": null, "args": null, @@ -285,12 +325,12 @@ return { "name": "person", "plural": false, "selections": [ - (v9/*: any*/), - (v3/*: any*/) + (v13/*: any*/), + (v6/*: any*/) ], "storageKey": null }, - (v10/*: any*/), + (v14/*: any*/), { "alias": null, "args": null, @@ -307,8 +347,8 @@ return { "name": "nodes", "plural": true, "selections": [ - (v11/*: any*/), - (v3/*: any*/) + (v15/*: any*/), + (v6/*: any*/) ], "storageKey": null } @@ -343,16 +383,16 @@ return { ] }, "params": { - "cacheID": "7f6407c93dce3445c4857b72dcae3cef", + "cacheID": "fc2878e1e17aa985e841f3674c259328", "id": null, "metadata": {}, "name": "DuplicateMealPlanMutation", "operationKind": "mutation", - "text": "mutation DuplicateMealPlanMutation(\n $mealPlanId: BigInt!\n) {\n duplicateMealPlan(input: {mealplanId: $mealPlanId}) {\n mealPlanEdge {\n cursor\n node {\n id\n rowId\n nameEn\n nameFr\n descriptionEn\n descriptionFr\n person {\n fullName\n id\n }\n tags\n mealPlanEntries {\n nodes {\n meal {\n id\n photoUrl\n }\n id\n }\n }\n }\n }\n }\n}\n" + "text": "mutation DuplicateMealPlanMutation(\n $mealPlanId: BigInt!\n $personId: BigInt!\n $duplicateNameEn: String!\n) {\n duplicateMealPlan(input: {mealplanId: $mealPlanId, pId: $personId, dupNameEn: $duplicateNameEn}) {\n mealPlanEdge {\n cursor\n node {\n id\n rowId\n nameEn\n nameFr\n personId\n descriptionEn\n descriptionFr\n person {\n fullName\n id\n }\n tags\n mealPlanEntries {\n nodes {\n meal {\n id\n photoUrl\n }\n id\n }\n }\n }\n }\n }\n}\n" } }; })(); -(node as any).hash = "42d544842c1e18d7facbf151b2a90b65"; +(node as any).hash = "8c3913ee5651e63453484de65fc3ff84"; export default node; diff --git a/mealplanner-ui/src/pages/MealPlans/__generated__/MealPlansQuery.graphql.ts b/mealplanner-ui/src/pages/MealPlans/__generated__/MealPlansQuery.graphql.ts index 41fe34fb..895fc496 100644 --- a/mealplanner-ui/src/pages/MealPlans/__generated__/MealPlansQuery.graphql.ts +++ b/mealplanner-ui/src/pages/MealPlans/__generated__/MealPlansQuery.graphql.ts @@ -20,7 +20,6 @@ export type MealPlansQuery$data = { readonly id: string; readonly rowId: any; readonly nameEn: string; - readonly personId: any | null; readonly descriptionEn: string | null; readonly isTemplate: boolean | null; readonly person: {