From c40be6381e5f12331d4fc640b04fffc831a774b6 Mon Sep 17 00:00:00 2001 From: cade Date: Thu, 29 Aug 2024 14:57:04 -0600 Subject: [PATCH] add training plan templates --- .../training-plans/create/page.tsx | 18 +- .../templates/sessions/[templateId]/page.tsx | 2 +- .../create/from-session/[sessionId]/page.tsx | 2 +- .../templates/sessions/create/page.tsx | 2 +- .../training-plans/[templateId]/loading.tsx | 5 + .../training-plans/[templateId]/page.tsx | 55 ++++ .../[trainingPlanId]/loading.tsx | 5 + .../[trainingPlanId]/page.tsx | 69 ++++ .../training-plans/create/loading.tsx | 5 + .../templates/training-plans/create/page.tsx | 44 +++ app/_components/event-menu.tsx | 2 +- app/_components/event-type-menu.tsx | 4 +- app/_components/event-types.tsx | 5 +- app/_components/filterable-inputs.tsx | 5 +- app/_components/filterable-templates.tsx | 5 +- app/_components/input-menu.tsx | 4 +- app/_components/insight-menu.tsx | 4 +- app/_components/module-form-section.tsx | 111 ++++--- app/_components/session-form-section.tsx | 242 ++++++++++++++ app/_components/session-form.tsx | 188 +---------- app/_components/session-menu.tsx | 21 +- app/_components/session-template-form.tsx | 84 ++--- app/_components/sessions-page.tsx | 2 +- .../sortable-session-form-section.tsx | 310 ++++++++++++++++++ app/_components/subject-list.tsx | 5 +- app/_components/subject-menu.tsx | 4 +- app/_components/template-menu.tsx | 2 +- app/_components/training-plan-menu.tsx | 4 +- .../training-plan-template-form.tsx | 209 ++++++++++++ .../training-plan-use-template-modal.tsx | 115 ++++--- app/_components/training-plans.tsx | 5 +- .../create-training-plan-from-template.ts | 60 ++++ .../upsert-training-plan-template.ts | 39 +++ app/_queries/get-template.ts | 2 +- .../get-training-plan-for-template.ts | 27 ++ app/_queries/list-templates.ts | 15 +- .../training-plan-template-data-json.ts | 10 + app/_utilities/get-form-cache-key.ts | 5 + 38 files changed, 1324 insertions(+), 372 deletions(-) create mode 100644 app/(pages)/@modal/(layout)/templates/training-plans/[templateId]/loading.tsx create mode 100644 app/(pages)/@modal/(layout)/templates/training-plans/[templateId]/page.tsx create mode 100644 app/(pages)/@modal/(layout)/templates/training-plans/create/from-training-plan/[trainingPlanId]/loading.tsx create mode 100644 app/(pages)/@modal/(layout)/templates/training-plans/create/from-training-plan/[trainingPlanId]/page.tsx create mode 100644 app/(pages)/@modal/(layout)/templates/training-plans/create/loading.tsx create mode 100644 app/(pages)/@modal/(layout)/templates/training-plans/create/page.tsx create mode 100644 app/_components/session-form-section.tsx create mode 100644 app/_components/sortable-session-form-section.tsx create mode 100644 app/_components/training-plan-template-form.tsx create mode 100644 app/_mutations/create-training-plan-from-template.ts create mode 100644 app/_mutations/upsert-training-plan-template.ts create mode 100644 app/_queries/get-training-plan-for-template.ts create mode 100644 app/_types/training-plan-template-data-json.ts diff --git a/app/(pages)/@modal/(layout)/subjects/[subjectId]/training-plans/create/page.tsx b/app/(pages)/@modal/(layout)/subjects/[subjectId]/training-plans/create/page.tsx index 039caab5..53ffa02b 100644 --- a/app/(pages)/@modal/(layout)/subjects/[subjectId]/training-plans/create/page.tsx +++ b/app/(pages)/@modal/(layout)/subjects/[subjectId]/training-plans/create/page.tsx @@ -2,7 +2,9 @@ import * as Modal from '@/_components/modal'; import PageModalHeader from '@/_components/page-modal-header'; import TrainingPlanForm from '@/_components/training-plan-form'; import TrainingPlanUseTemplateModal from '@/_components/training-plan-use-template-modal'; +import TemplateType from '@/_constants/enum-template-type'; import getSubject from '@/_queries/get-subject'; +import listTemplates from '@/_queries/list-templates'; interface PageProps { params: { @@ -11,13 +13,23 @@ interface PageProps { } const Page = async ({ params: { subjectId } }: PageProps) => { - const { data: subject } = await getSubject(subjectId); - if (!subject) return null; + const [{ data: availableTrainingPlanTemplates }, { data: subject }] = + await Promise.all([ + listTemplates({ type: TemplateType.TrainingPlan }), + getSubject(subjectId), + ]); + + if (!availableTrainingPlanTemplates || !subject) return null; return ( } + right={ + + } title="New training plan" /> diff --git a/app/(pages)/@modal/(layout)/templates/sessions/[templateId]/page.tsx b/app/(pages)/@modal/(layout)/templates/sessions/[templateId]/page.tsx index 842e3d89..cbfd69c5 100644 --- a/app/(pages)/@modal/(layout)/templates/sessions/[templateId]/page.tsx +++ b/app/(pages)/@modal/(layout)/templates/sessions/[templateId]/page.tsx @@ -35,7 +35,7 @@ const Page = async ({ params: { templateId } }: PageProps) => { diff --git a/app/(pages)/@modal/(layout)/templates/sessions/create/from-session/[sessionId]/page.tsx b/app/(pages)/@modal/(layout)/templates/sessions/create/from-session/[sessionId]/page.tsx index 07ea9101..9e8e2298 100644 --- a/app/(pages)/@modal/(layout)/templates/sessions/create/from-session/[sessionId]/page.tsx +++ b/app/(pages)/@modal/(layout)/templates/sessions/create/from-session/[sessionId]/page.tsx @@ -35,7 +35,7 @@ const Page = async ({ params: { sessionId } }: PageProps) => { { diff --git a/app/(pages)/@modal/(layout)/templates/training-plans/[templateId]/loading.tsx b/app/(pages)/@modal/(layout)/templates/training-plans/[templateId]/loading.tsx new file mode 100644 index 00000000..e3d948d8 --- /dev/null +++ b/app/(pages)/@modal/(layout)/templates/training-plans/[templateId]/loading.tsx @@ -0,0 +1,5 @@ +import PageModalLoading from '@/_components/page-modal-loading'; + +const Loading = PageModalLoading; + +export default Loading; diff --git a/app/(pages)/@modal/(layout)/templates/training-plans/[templateId]/page.tsx b/app/(pages)/@modal/(layout)/templates/training-plans/[templateId]/page.tsx new file mode 100644 index 00000000..6228f0b0 --- /dev/null +++ b/app/(pages)/@modal/(layout)/templates/training-plans/[templateId]/page.tsx @@ -0,0 +1,55 @@ +import * as Modal from '@/_components/modal'; +import PageModalHeader from '@/_components/page-modal-header'; +import TrainingPlanTemplateForm from '@/_components/training-plan-template-form'; +import TemplateType from '@/_constants/enum-template-type'; +import getTemplate from '@/_queries/get-template'; +import listInputs from '@/_queries/list-inputs'; +import listSubjectsByTeamId from '@/_queries/list-subjects-by-team-id'; +import listTemplatesWithData from '@/_queries/list-templates-with-data'; + +interface PageProps { + params: { + templateId: string; + }; +} + +const Page = async ({ params: { templateId } }: PageProps) => { + const [ + { data: availableInputs }, + { data: availableModuleTemplates }, + { data: availableSessionTemplates }, + { data: subjects }, + { data: template }, + ] = await Promise.all([ + listInputs(), + listTemplatesWithData({ type: TemplateType.Module }), + listTemplatesWithData({ type: TemplateType.Session }), + listSubjectsByTeamId(), + getTemplate(templateId), + ]); + + if ( + !availableInputs || + !availableModuleTemplates || + !availableSessionTemplates || + !subjects || + !template + ) { + return null; + } + + return ( + + + + + ); +}; + +export default Page; diff --git a/app/(pages)/@modal/(layout)/templates/training-plans/create/from-training-plan/[trainingPlanId]/loading.tsx b/app/(pages)/@modal/(layout)/templates/training-plans/create/from-training-plan/[trainingPlanId]/loading.tsx new file mode 100644 index 00000000..e3d948d8 --- /dev/null +++ b/app/(pages)/@modal/(layout)/templates/training-plans/create/from-training-plan/[trainingPlanId]/loading.tsx @@ -0,0 +1,5 @@ +import PageModalLoading from '@/_components/page-modal-loading'; + +const Loading = PageModalLoading; + +export default Loading; diff --git a/app/(pages)/@modal/(layout)/templates/training-plans/create/from-training-plan/[trainingPlanId]/page.tsx b/app/(pages)/@modal/(layout)/templates/training-plans/create/from-training-plan/[trainingPlanId]/page.tsx new file mode 100644 index 00000000..87a3d476 --- /dev/null +++ b/app/(pages)/@modal/(layout)/templates/training-plans/create/from-training-plan/[trainingPlanId]/page.tsx @@ -0,0 +1,69 @@ +import * as Modal from '@/_components/modal'; +import PageModalHeader from '@/_components/page-modal-header'; +import TrainingPlanTemplateForm from '@/_components/training-plan-template-form'; +import TemplateType from '@/_constants/enum-template-type'; +import getTrainingPlanForTemplate from '@/_queries/get-training-plan-for-template'; +import listInputs from '@/_queries/list-inputs'; +import listSubjectsByTeamId from '@/_queries/list-subjects-by-team-id'; +import listTemplatesWithData from '@/_queries/list-templates-with-data'; + +interface PageProps { + params: { + trainingPlanId: string; + }; +} + +const Page = async ({ params: { trainingPlanId } }: PageProps) => { + const [ + { data: availableInputs }, + { data: availableModuleTemplates }, + { data: availableSessionTemplates }, + { data: subjects }, + { data: trainingPlan }, + ] = await Promise.all([ + listInputs(), + listTemplatesWithData({ type: TemplateType.Module }), + listTemplatesWithData({ type: TemplateType.Session }), + listSubjectsByTeamId(), + getTrainingPlanForTemplate(trainingPlanId), + ]); + + if ( + !availableInputs || + !availableModuleTemplates || + !availableSessionTemplates || + !subjects || + !trainingPlan + ) { + return null; + } + + return ( + + + ({ + modules: session.modules.map((module) => ({ + content: module.content, + inputIds: module.inputs.map((input) => input.id), + name: module.name, + })), + title: session.title, + })), + }, + name: trainingPlan.name ?? '', + }} + /> + + ); +}; + +export default Page; diff --git a/app/(pages)/@modal/(layout)/templates/training-plans/create/loading.tsx b/app/(pages)/@modal/(layout)/templates/training-plans/create/loading.tsx new file mode 100644 index 00000000..e3d948d8 --- /dev/null +++ b/app/(pages)/@modal/(layout)/templates/training-plans/create/loading.tsx @@ -0,0 +1,5 @@ +import PageModalLoading from '@/_components/page-modal-loading'; + +const Loading = PageModalLoading; + +export default Loading; diff --git a/app/(pages)/@modal/(layout)/templates/training-plans/create/page.tsx b/app/(pages)/@modal/(layout)/templates/training-plans/create/page.tsx new file mode 100644 index 00000000..dd2ee5dc --- /dev/null +++ b/app/(pages)/@modal/(layout)/templates/training-plans/create/page.tsx @@ -0,0 +1,44 @@ +import * as Modal from '@/_components/modal'; +import PageModalHeader from '@/_components/page-modal-header'; +import TrainingPlanTemplateForm from '@/_components/training-plan-template-form'; +import TemplateType from '@/_constants/enum-template-type'; +import listInputs from '@/_queries/list-inputs'; +import listSubjectsByTeamId from '@/_queries/list-subjects-by-team-id'; +import listTemplatesWithData from '@/_queries/list-templates-with-data'; + +const Page = async () => { + const [ + { data: availableInputs }, + { data: availableModuleTemplates }, + { data: availableSessionTemplates }, + { data: subjects }, + ] = await Promise.all([ + listInputs(), + listTemplatesWithData({ type: TemplateType.Module }), + listTemplatesWithData({ type: TemplateType.Session }), + listSubjectsByTeamId(), + ]); + + if ( + !availableInputs || + !availableModuleTemplates || + !availableSessionTemplates || + !subjects + ) { + return null; + } + + return ( + + + + + ); +}; + +export default Page; diff --git a/app/_components/event-menu.tsx b/app/_components/event-menu.tsx index 24fe3530..ec3b4d90 100644 --- a/app/_components/event-menu.tsx +++ b/app/_components/event-menu.tsx @@ -29,7 +29,7 @@ const EventMenu = ({ className, eventId, isModal }: EventMenuProps) => { className, )} > -
+
diff --git a/app/_components/event-type-menu.tsx b/app/_components/event-type-menu.tsx index 7daf0898..b86e0234 100644 --- a/app/_components/event-type-menu.tsx +++ b/app/_components/event-type-menu.tsx @@ -28,8 +28,8 @@ const EventTypeMenu = ({ {isModal ? ( } /> ) : ( -
-
+
+
diff --git a/app/_components/event-types.tsx b/app/_components/event-types.tsx index 65150a92..64a92f7b 100644 --- a/app/_components/event-types.tsx +++ b/app/_components/event-types.tsx @@ -16,7 +16,10 @@ const EventTypes = async ({ isTeamMember, subjectId }: EventTypesProps) => { return (
    {eventTypes.map((eventType) => ( -
  • +
    {filteredInputs.map((input) => ( -
  • +