ソースを参照

added new program. added archive support.

Tomi Cvetic 4 年 前
コミット
1997c10a17

+ 5 - 1
.vscode/settings.json

@@ -10,5 +10,9 @@
     "editor.fontLigatures": true,
     "files.trimTrailingWhitespace": true,
     "workbench.colorTheme": "Cobalt2",
-    "editor.tabSize": 2
+    "editor.tabSize": 2,
+    "prettier.jsxSingleQuote": true,
+    "prettier.printWidth": 100,
+    "prettier.semi": false,
+    "prettier.singleQuote": true
 }

ファイルの差分が大きいため隠しています
+ 514 - 373
backend/database/generated/prisma.graphql


+ 51 - 21
backend/datamodel.prisma

@@ -6,10 +6,10 @@ type User {
     resetToken: String
     resetTokenExpiry: Float
     createdAt: DateTime! @createdAt
-    comments: [Comment]!
-    ratings: [Rating]!
-    permissions: [Permission]!  @scalarList(strategy: RELATION)
-    interests: [String]!  @scalarList(strategy: RELATION)
+    comments: [Comment!]!
+    ratings: [Rating!]!
+    permissions: [Permission!]!  @scalarList(strategy: RELATION)
+    interests: [String!]!  @scalarList(strategy: RELATION)
 }
 
 enum Permission {
@@ -17,18 +17,32 @@ enum Permission {
     INSTRUCTOR
 }
 
+type File {
+    id: ID! @id
+    createdAt: DateTime! @createdAt
+    updatedAt: DateTime! @updatedAt
+    path: String!
+    mimetype: String!
+    user: User!
+    thumbnail: String
+    filename: String!
+    encoding: String!
+    size: Int!
+    comment: String
+}
+
 type Training {
     id: ID! @id
     title: String!
     type: TrainingType!
-    content: [Block]!
     createdAt: DateTime! @createdAt
     trainingDate: DateTime!
     location: String!
-    registration: [User]!
-    attendance: Int!
-    ratings: [Rating]!
+    registrations: [User!]!
+    attendance: Int
+    ratings: [Rating!]!
     published: Boolean!
+    blocks: [BlockInstance!]! @relation(onDelete: CASCADE)
 }
 
 type TrainingType {
@@ -39,14 +53,27 @@ type TrainingType {
 
 type Block {
     id: ID! @id
-    sequence: Int!
     title: String!
-    duration: Int!
+    description: String
+    videos: [String!]! @scalarList(strategy: RELATION)
+    pictures: [String!]! @scalarList(strategy: RELATION)
+    duration: Int
+    format: Format!
+    rest: Int
+    tracks: [Track!]!
+    blocks: [BlockInstance!] @relation(name: "Instances", onDelete: CASCADE)
+    links: [BlockInstance!]! @relation(name: "ParentChild", onDelete: CASCADE)
+    exercises: [ExerciseInstance!]! @relation(onDelete: CASCADE)
+}
+
+type BlockInstance {
+    id: ID! @id
+    block: Block! @relation(name: "ParentChild", onDelete: SET_NULL)
+    parentBlock: Block @relation(name: "Instances")
+    parentTraining: Training @relation(link: INLINE)
+    order: Int!
+    rounds: Int
     variation: String
-    format: Format
-    tracks: [Track]!
-    exercises: [Exercise]!
-    description: String!
 }
 
 type Format {
@@ -66,16 +93,19 @@ type Track {
 type Exercise {
     id: ID! @id
     name: String!
-    description: String!
-    video: String!
-    targets: [String]! @scalarList(strategy: RELATION)
-    baseExercise: BaseExercise!
+    description: String
+    videos: [String!]! @scalarList(strategy: RELATION)
+    pictures: [String!]! @scalarList(strategy: RELATION)
+    targets: [String!]! @scalarList(strategy: RELATION)
+    baseExercise: [String!]! @scalarList(strategy: RELATION)
 }
 
-type BaseExercise {
+type ExerciseInstance {
     id: ID! @id
-    name: String!
-    variations: [Exercise]!
+    exercise: Exercise! @relation(link: INLINE)
+    order: Int!
+    repetitions: Int
+    variation: String
 }
 
 type Rating {

+ 89 - 26
backend/schema.graphql

@@ -1,16 +1,24 @@
 # import * from './database/generated/prisma.graphql'
 
+scalar Upload
+
+type FsFile {
+  filename: String!
+  path: String!
+  size: Int!
+  ctime: DateTime!
+  mtime: DateTime!
+}
+
 type Query {
-  users(
-    where: UserWhereInput
-    orderBy: UserOrderByInput
+  # Training module
+  publishedTrainings(
+    where: TrainingWhereInput
+    orderBy: TrainingOrderByInput
     skip: Int
-    after: String
-    before: String
     first: Int
-    last: Int
-  ): [User]!
-  training(where: TrainingWhereUniqueInput!): Training
+  ): [Training!]!
+  training(id: ID): Training!
   trainings(
     where: TrainingWhereInput
     orderBy: TrainingOrderByInput
@@ -19,7 +27,24 @@ type Query {
     before: String
     first: Int
     last: Int
-  ): [Training]!
+  ): [Training!]!
+  trainingsCount(where: TrainingWhereInput): TrainingConnection!
+
+  # File module
+  fsFiles(directory: String!): [FsFile!]!
+  files: [File!]!
+  currentUser: User!
+  user(where: UserWhereUniqueInput!): User
+  users(
+    where: UserWhereInput
+    orderBy: UserOrderByInput
+    skip: Int
+    after: String
+    before: String
+    first: Int
+    last: Int
+  ): [User!]!
+  trainingType(where: TrainingTypeWhereUniqueInput!): TrainingType
   trainingTypes(
     where: TrainingTypeWhereInput
     orderBy: TrainingTypeOrderByInput
@@ -28,7 +53,8 @@ type Query {
     before: String
     first: Int
     last: Int
-  ): [TrainingType]!
+  ): [TrainingType!]!
+  block(where: BlockWhereUniqueInput!): Block
   blocks(
     where: BlockWhereInput
     orderBy: BlockOrderByInput
@@ -37,29 +63,66 @@ type Query {
     before: String
     first: Int
     last: Int
-  ): [Block]!
-  currentUser: User!
+  ): [Block!]!
+  format(where: FormatWhereUniqueInput!): Format
+  formats(
+    where: FormatWhereInput
+    orderBy: FormatOrderByInput
+    skip: Int
+    after: String
+    before: String
+    first: Int
+    last: Int
+  ): [Format!]!
+  exercise(where: ExerciseWhereUniqueInput!): Exercise
+  exercises(
+    where: ExerciseWhereInput
+    orderBy: ExerciseOrderByInput
+    skip: Int
+    after: String
+    before: String
+    first: Int
+    last: Int
+  ): [Exercise!]!
 }
 
 type Mutation {
+  # File module
+  uploadFile(file: Upload!, comment: String): File!
+
   createUser(data: UserCreateInput!): User!
   updateUser(email: String!, data: UserUpdateInput!): User
   deleteUser(email: String!): User
-  createTraining(title: String!): Training!
-  createTrainingType(name: String!, description: String!): TrainingType!
-  createBlock(
-    sequence: Int!
+  createTraining(
     title: String!
-    duration: Int!
-    variation: String
-    format: ID
-    tracks: [ID]!
-    exercises: [ID]!
-    description: String!
-  ): Block!
-  login(email: String!, password: String!): User!
-  logout: String!
-  signup(name: String!, email: String!, password: String!): User!
+    type: TrainingTypeCreateOneInput!
+    trainingDate: DateTime!
+    location: String!
+    attendance: Int
+    published: Boolean!
+    blocks: BlockInstanceCreateManyWithoutParentTrainingInput
+  ): Training!
+  updateTraining(where: TrainingWhereUniqueInput!, data: TrainingUpdateInput!): Training!
+  createTrainingType(name: String!, description: String!): TrainingType!
+  # createBlock(
+  #   title: String!
+  #   description: String
+  #   videos: [String!]
+  #   pictures: [String!]
+  #   duration: Int
+  #   format: FormatCreateOneInput!
+  #   rest: Int
+  #   tracks: TrackCreateManyInput
+  #   blocks: BlockInstanceCreateManyInput
+  #   exercises: ExerciseInstanceCreateManyInput
+  # ): Block!
+  createFormat(name: String!, description: String!): Format!
+  userLogin(email: String!, password: String!): User!
+  userLogout: String!
+  userSignup(name: String!, email: String!, password: String!): User!
   requestReset(email: String!): String!
   resetPassword(token: String!, password: String!): User!
+  register(training: ID!): Training!
+  deregister(training: ID!): Training!
+  publish(training: ID!, status: Boolean): Training!
 }

+ 0 - 0
frontend/initial-data.ts → frontend/circuit1.ts


+ 882 - 0
frontend/circuit2.ts

@@ -0,0 +1,882 @@
+import { ITraining } from './src/training/types'
+
+const data: { trainings: ITraining[]; polls: any } = {
+  trainings: [
+    {
+      id: 'training0',
+      title: 'Circuit 2',
+      type: {
+        id: 'type0',
+        name: 'HIIT',
+        description: 'High intensity interval training.',
+      },
+      createdAt: '2020-04-14T21:13:43.284Z',
+      trainingDate: '2020-04-15T09:45:00.000Z',
+      location: 'At home',
+      registrations: [],
+      attendance: 0,
+      ratings: [],
+      published: true,
+      blocks: [
+        {
+          id: 'block1',
+          sequence: 0,
+          title: 'Tabata',
+          repetitions: 1,
+          rest: 60,
+          video: '/media/tabata2-1.mp4',
+          format: {
+            id: 'format0',
+            name: 'Sequence',
+            description: 'Sequence of exercises',
+          },
+          blocks: [
+            {
+              id: 'block4',
+              duration: 10,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Prepare',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block1',
+              duration: 20,
+              description: 'Get the pulse up as fast as possible.',
+              rest: 10,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Seal jacks',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block2',
+              duration: 20,
+              description:
+                "Keep your abs tight. Try to to it against the wall (it's harder), but you can use some books instead to step on.",
+              rest: 10,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Wall pushup',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block3',
+              duration: 20,
+              rest: 10,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Low squat',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+                {
+                  id: 'exercise1',
+                  name: '180',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block4',
+              duration: 20,
+              description: 'The higher you can keep your pelvis, the harder it gets.',
+              rest: 10,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Tabletop toe reacher',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block5',
+              duration: 20,
+              description: '',
+              rest: 10,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'High knees',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block6',
+              duration: 20,
+              rest: 10,
+              description:
+                'Punch between the thighs then outside. Stay with the beat, use the full range.',
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Punch crunch',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block7',
+              duration: 20,
+              rest: 10,
+              description: '',
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Triple lunge pulses',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block8',
+              duration: 20,
+              description: 'Knees go straight, cross, straight, out',
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Switch climber',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+          ],
+        },
+        {
+          id: 'block1',
+          sequence: 0,
+          title: 'Tabata',
+          repetitions: 1,
+          rest: 60,
+          video: '/media/tabata2-2.mp4',
+          format: {
+            id: 'format0',
+            name: 'Sequence',
+            description: 'Sequence of exercises',
+          },
+          blocks: [
+            {
+              id: 'block4',
+              duration: 10,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Prepare',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block1',
+              duration: 20,
+              description: 'Get the pulse up as fast as possible.',
+              rest: 10,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Seal jacks',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block2',
+              duration: 20,
+              description:
+                "Keep your abs tight. Try to to it against the wall (it's harder), but you can use some books instead to step on.",
+              rest: 10,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Wall pushup',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block3',
+              duration: 20,
+              rest: 10,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Low squat',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+                {
+                  id: 'exercise1',
+                  name: '180',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block4',
+              duration: 20,
+              description: 'The higher you can keep your pelvis, the harder it gets.',
+              rest: 10,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Tabletop toe reacher',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block5',
+              duration: 20,
+              description: '',
+              rest: 10,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'High knees',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block6',
+              duration: 20,
+              rest: 10,
+              description:
+                'Punch between the thighs then outside. Stay with the beat, use the full range.',
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Punch crunch',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block7',
+              duration: 20,
+              rest: 10,
+              description: '',
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Triple lunge pulses',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block8',
+              duration: 20,
+              description: 'Knees go straight, cross, straight, out',
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Switch climber',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+          ],
+        },
+        {
+          id: 'block0',
+          sequence: 0,
+          title: 'Circuit',
+          repetitions: 2,
+          rest: 60,
+          format: {
+            id: 'format0',
+            name: 'Sequence',
+            description: 'Sequence of exercises',
+          },
+          blocks: [
+            {
+              id: 'block1',
+              duration: 45,
+              rest: 15,
+              description: 'Lift left arm, left leg, right leg, right arm when coming up',
+              video: '/media/circuit2-1.mp4',
+              exercises: [
+                {
+                  id: 'exercise0',
+                  name: 'Around the world pushup',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: [],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Jog on the spot',
+                  },
+                },
+                {
+                  id: 'exercise0',
+                  name: 'Around the world superman',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: [],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Jog on the spot',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block2',
+              duration: 45,
+              rest: 15,
+              description:
+                'Always start with the same leg: Forward, sideways, back, sideways. Change the starting leg in the second round!',
+              video: '/media/circuit2-2.mp4',
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Fast feet cross',
+                  repetitions: 1,
+                  description:
+                    'Sit down backwards, hip about knee-high. Keep your knees behind the toes.',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block3',
+              duration: 45,
+              rest: 15,
+              description: '',
+              video: '/media/circuit2-3.mp4',
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Adductor/abductor combo',
+                  repetitions: 1,
+                  description:
+                    'Sit down backwards, hip about knee-high. Keep your knees behind the toes.',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block4',
+              duration: 45,
+              rest: 15,
+              video: '/media/circuit2-4.mp4',
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Squat - lunge - squat - kick',
+                  repetitions: 1,
+                  description:
+                    'Sit down backwards, hip about knee-high. Keep your knees behind the toes.',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block5',
+              duration: 45,
+              rest: 15,
+              video: '/media/circuit2-5.mp4',
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Pushup - toe touch',
+                  repetitions: 1,
+                  description:
+                    'Sit down backwards, hip about knee-high. Keep your knees behind the toes.',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block6',
+              duration: 45,
+              rest: 15,
+              video: '/media/circuit2-6.mp4',
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'High jumps',
+                  repetitions: 4,
+                  description:
+                    'Sit down backwards, hip about knee-high. Keep your knees behind the toes.',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+                {
+                  id: 'exercise1',
+                  name: 'Surfer jumps',
+                  repetitions: 4,
+                  description:
+                    'Sit down backwards, hip about knee-high. Keep your knees behind the toes.',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+          ],
+        },
+        {
+          id: 'block0',
+          sequence: 0,
+          title: 'Burpee challenge',
+          description: '4 Burpee variations. Start with 1 repetition each, then go for 2, 3, 4...',
+          repetitions: 1,
+          rest: 60,
+          format: {
+            id: 'format0',
+            name: 'Challenge',
+            description: 'Finish 6 repetitions and earn a break.',
+          },
+          blocks: [
+            {
+              id: 'block2',
+              duration: 120,
+              video: '/media/burpeechallenge.mp4',
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Burpee',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+                {
+                  id: 'exercise1',
+                  name: 'Pushup burpee',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+                {
+                  id: 'exercise1',
+                  name: 'Pushup tuck jump burpee',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+                {
+                  id: 'exercise1',
+                  name: 'Hands off push up tuck jump burpee',
+                  repetitions: 1,
+                  description: '',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+          ],
+        },
+        {
+          id: 'block0',
+          sequence: 0,
+          title: 'Running Low',
+          repetitions: 1,
+          video: '/media/runninglow.mp4',
+          format: {
+            id: 'format0',
+            name: 'Sequence',
+            description: 'Sequence of exercises',
+          },
+          blocks: [
+            {
+              id: 'block2',
+              duration: 13,
+              exercises: [
+                {
+                  id: 'exercise0',
+                  name: 'Into',
+                  repetitions: 1,
+                  description: '',
+                  videos: ['https://www.youtube.com/watch?v=s5GanRixp6I'],
+                  pictures: [
+                    'https://media1.popsugar-assets.com/files/thumbor/xfgCQbEWOZpPDA_HTMSfgcOnYYE/fit-in/1024x1024/filters:format_auto-!!-:strip_icc-!!-/2015/06/26/981/n/1922729/a7719ba19ea7a1ae_lateral-run-and-hold/i/Tabata-One-Lateral-High-Knee-Run-Hold.jpg',
+                  ],
+                  targets: [],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Jog on the spot',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block3',
+              duration: 44,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Transversus crunch',
+                  repetitions: 1,
+                  description:
+                    'Sit down backwards, hip about knee-high. Keep your knees behind the toes.',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block4',
+              duration: 22,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Leg extension/split combo',
+                  repetitions: 1,
+                  description:
+                    'Sit down backwards, hip about knee-high. Keep your knees behind the toes.',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block4',
+              duration: 23,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Bicycle crunch',
+                  repetitions: 1,
+                  description:
+                    'Sit down backwards, hip about knee-high. Keep your knees behind the toes.',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block4',
+              duration: 27,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Hover',
+                  repetitions: 1,
+                  description:
+                    'Sit down backwards, hip about knee-high. Keep your knees behind the toes.',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block4',
+              duration: 23,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Hover jack',
+                  repetitions: 1,
+                  description:
+                    'Sit down backwards, hip about knee-high. Keep your knees behind the toes.',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block4',
+              duration: 22,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Hover - plank',
+                  repetitions: 1,
+                  description:
+                    'Sit down backwards, hip about knee-high. Keep your knees behind the toes.',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+            {
+              id: 'block4',
+              duration: 25,
+              exercises: [
+                {
+                  id: 'exercise1',
+                  name: 'Hover - plank + jack combo',
+                  repetitions: 1,
+                  description:
+                    'Sit down backwards, hip about knee-high. Keep your knees behind the toes.',
+                  videos: [],
+                  pictures: [],
+                  targets: ['Thighs', 'Glutes'],
+                  baseExercise: {
+                    id: 'baseExercise1',
+                    name: 'Squat',
+                  },
+                },
+              ],
+            },
+          ],
+        },
+      ],
+    },
+  ],
+  polls: [],
+}
+
+export default data

+ 3 - 0
frontend/pages/[id].tsx

@@ -0,0 +1,3 @@
+import Home from './index'
+
+export default Home

+ 15 - 3
frontend/pages/_app.tsx

@@ -5,6 +5,16 @@ import Page from '../src/app/components/Page'
 import client from '../src/lib/apollo'
 import { StoreProvider } from '../src/lib/store'
 
+import circuit2 from '../circuit2'
+import circuit1 from '../circuit1'
+import homework from '../homework'
+import corona1 from '../corona1'
+import { createContext } from 'react'
+
+const trainings = [corona1, homework, circuit1, circuit2]
+
+export const TrainingContext = createContext(trainings)
+
 class MyApp extends App {
   static async getInitialProps({ Component, ctx }: any) {
     let pageProps: any = {}
@@ -24,9 +34,11 @@ class MyApp extends App {
 
     return (
       <ApolloProvider client={client}>
-        <Page>
-          <Component {...pageProps} />
-        </Page>
+        <TrainingContext.Provider value={trainings}>
+          <Page>
+            <Component {...pageProps} />
+          </Page>
+        </TrainingContext.Provider>
       </ApolloProvider>
     )
   }

+ 24 - 7
frontend/pages/index.tsx

@@ -1,17 +1,29 @@
 import Link from 'next/link'
-
-import initialData from '../initial-data'
-import { useTrainingsQuery } from '../src/gql'
 import { Training } from '../src/training'
-
-console.log(initialData)
+import { useContext, useState, useEffect } from 'react'
+import { TrainingContext } from './_app'
+import TrainingArchive from '../src/training/components/TrainingArchive'
+import { useRouter } from 'next/router'
 
 const Home = () => {
   //const { data, error, loading } = useTrainingsQuery();
+  const trainingList = useContext(TrainingContext)
+  const [trainingIndex, setTrainingIndex] = useState(trainingList.length - 1)
+  const router = useRouter()
+  const queryId = router.query && router.query.id
+
+  useEffect(() => {
+    if (typeof queryId !== 'string') return
+    const intId = parseInt(queryId)
+    if (intId < 0 || intId + 1 > trainingList.length) return
+    setTrainingIndex(intId)
+  }, [router.query])
+
+  const { trainings } = trainingList[trainingIndex]
 
   return (
     <>
-      <section>
+      <section className='training-meta'>
         <h1>Stay in Shape with u-fit</h1>
         <p>u-fit is a high intensity interval training offered by u-blox.</p>
         <aside>
@@ -27,11 +39,16 @@ const Home = () => {
       </section>
 
       <section id='nextTraining'>
-        <Training training={initialData.trainings[0]} />
+        <Training index={trainingIndex} training={trainings[0]} />
       </section>
 
+      <TrainingArchive />
+
       <style jsx>
         {`
+          .training-meta {
+            padding: 0 1em;
+          }
           .info .caption {
             display: inline-block;
             font-weight: 900;

+ 18 - 2
frontend/pages/timer.tsx

@@ -1,8 +1,24 @@
-import initialData from '../initial-data'
 import { Timer } from '../src/timer'
+import { useContext, useState, useEffect } from 'react'
+import { TrainingContext } from './_app'
+import { useRouter } from 'next/router'
 
 const TimerPage = () => {
-  return <Timer training={initialData.trainings[0]} />
+  const trainingList = useContext(TrainingContext)
+  const [trainingIndex, setTrainingIndex] = useState(trainingList.length - 1)
+  const router = useRouter()
+  const queryId = router.query && router.query.id
+
+  useEffect(() => {
+    if (typeof queryId !== 'string') return
+    const intId = parseInt(queryId)
+    if (intId < 0 || intId + 1 > trainingList.length) return
+    setTrainingIndex(intId)
+  }, [router.query])
+
+  const { trainings } = trainingList[trainingIndex]
+
+  return <Timer training={trainings[0]} />
 }
 
 export default TimerPage

+ 3 - 0
frontend/pages/timer/[id].tsx

@@ -0,0 +1,3 @@
+import TimerPage from '../timer'
+
+export default TimerPage

+ 3 - 0
frontend/pages/timer/index.tsx

@@ -0,0 +1,3 @@
+import TimerPage from '../timer'
+
+export default TimerPage

+ 50 - 30
frontend/src/app/components/Logo.tsx

@@ -1,38 +1,58 @@
 import Link from 'next/link'
+import theme from '../../styles/theme'
 
 const Logo = () => (
-  <Link href='/'>
-    <a>
-      <div id='logo'>
-        <span id='circle'>˙u</span>
-        <span id='text'>fit</span>
-      </div>
-      <style jsx>
-        {`
-          #logo {
-            position: relative;
-            height: 60px;
-            width: 60px;
-            color: white;
-            background-color: red;
-            border-radius: 30px;
-            font-size: 40px;
-            font-weight: 900;
-            padding: 10px 0 0 15px;
-          }
+  <h1 className='logo'>
+    <Link href='/'>
+      <a>
+        <span className='logo-circle'>u</span>
+        <span className='logo-text'>fit</span>
+      </a>
+    </Link>
+    <style jsx>
+      {`
+        .logo {
+          margin: 10px auto;
+        }
+        .logo span {
+          padding-top: 0.3em;
+          font-size: 40px;
+        }
+        .logo-circle {
+          position: relative;
+          display: inline-block;
+          text-align: right;
+          width: 1.55em;
+          height: 1.55em;
+          background-color: ${theme.colors.red};
+          border-radius: 50%;
+          font-weight: 900;
+          padding-right: 0.1em;
+        }
+        .logo-circle::before {
+          position: absolute;
+          content: '';
+          display: block;
+          width: 0.2em;
+          height: 0.2em;
+          border-radius: 50%;
+          background-color: white;
+          right: 40%;
+          bottom: 55%;
+        }
 
-          a {
-            text-decoration: none;
-          }
+        a {
+          text-decoration: none;
+          color: white;
+        }
 
-          #text {
-            color: black;
-            margin-left: 3px;
-          }
-        `}
-      </style>
-    </a>
-  </Link>
+        .logo .logo-text {
+          color: ${theme.colors.black};
+          margin-left: 0em;
+        }
+      `}
+    </style>
+  </h1>
 )
 
 export default Logo

ファイルの差分が大きいため隠しています
+ 657 - 199
frontend/src/gql/index.tsx


+ 5 - 4
frontend/src/training/components/Training.tsx

@@ -5,7 +5,8 @@ import Link from 'next/link'
 import { ITraining } from '../types'
 import TrainingMeta from './TrainingMeta'
 
-const Training = ({ training }: { training: ITraining }) => {
+const Training = ({ training, index }: { training: ITraining; index: number }) => {
+  console.log('Training', training, index)
   return (
     <article>
       <h2>{training.title}</h2>
@@ -14,13 +15,13 @@ const Training = ({ training }: { training: ITraining }) => {
 
       <section>
         <h2>Program</h2>
-        <Link href='/timer'>
+        <Link href='/timer/[id]' as={`/timer/${index}`}>
           <button>Start Timer</button>
         </Link>
         {training.blocks &&
           training.blocks
-            .sort(block => block.sequence || 0)
-            .map(block => <TrainingBlock key={block.id} block={block} />)}
+            //.sort((block) => block.sequence || 0)
+            .map((block, index) => <TrainingBlock key={index} block={block} />)}
       </section>
 
       <style jsx>

+ 83 - 0
frontend/src/training/components/TrainingArchive.tsx

@@ -0,0 +1,83 @@
+import { useState, useContext } from 'react'
+import TrainingHint from './TrainingHint'
+import theme from '../../styles/theme'
+import { TrainingContext } from '../../../pages/_app'
+
+const TrainingArchive = () => {
+  const trainingsPerPage = 4
+  const [state, setState] = useState(0)
+  const trainingsList = useContext(TrainingContext)
+
+  const count = trainingsList.length
+  const pages = []
+
+  for (let index = 0; index < count / trainingsPerPage; index++) {
+    pages.push(index)
+  }
+
+  return (
+    <section className='training-archive'>
+      <h2>Training Archive</h2>
+      <ul>
+        {trainingsList.map((training, index) => (
+          <TrainingHint key={index} index={index} training={training.trainings[0]} />
+        ))}
+      </ul>
+      {pages.map((index) => (
+        <button
+          key={index}
+          onClick={() => setState(index)}
+          className={index === state ? 'active' : undefined}
+        >
+          {index + 1}
+        </button>
+      ))}
+
+      <style jsx>{`
+        section {
+          margin: 1.5em 1em;
+        }
+        ul {
+          display: grid;
+          grid-template-columns: 1fr;
+          list-style: none;
+          margin: 1.2em 0;
+          padding: 0;
+        }
+        ul :global(a) {
+          text-decoration: none;
+          color: ${theme.colors.darkblue};
+        }
+        button {
+          display: inline;
+          border: none;
+          padding: 0.3em 0.6em;
+          margin: 0 0.3em;
+          background-color: transparent;
+          color: ${theme.colors.darkblue};
+          border-radius: 6px;
+          cursor: pointer;
+        }
+        button:hover {
+          background-color: ${theme.colors.darkblue}22;
+        }
+        button.active {
+          background-color: ${theme.colors.darkblue};
+          color: ${theme.colors.offWhite};
+        }
+        @media (min-width: 480px) {
+          ul {
+            grid-template-columns: 1fr 1fr;
+          }
+        }
+        @media (min-width: 1024px) {
+          ul {
+            grid-template-columns: repeat(4, 1fr);
+          }
+        }
+      `}</style>
+    </section>
+  )
+}
+
+export default TrainingArchive

+ 10 - 12
frontend/src/training/components/TrainingBlock.tsx

@@ -1,9 +1,10 @@
-import ExerciseComposition from "./ExerciseComposition";
-import { calculateDuration, formatTime } from "../utils";
-import { IBlock } from "../types";
+import ExerciseComposition from './ExerciseComposition'
+import { calculateDuration, formatTime } from '../utils'
+import { IBlock } from '../types'
 
 const TrainingBlock = ({ block }: { block: IBlock }) => {
-  const duration = calculateDuration(block);
+  console.log('Training Block', block)
+  const duration = calculateDuration(block)
   return (
     <div>
       {block.title && (
@@ -11,11 +12,8 @@ const TrainingBlock = ({ block }: { block: IBlock }) => {
           {block.title} ({formatTime(duration)})
         </h3>
       )}
-      {block.blocks &&
-        block.blocks.map(block => <TrainingBlock block={block} />)}
-      {block.exercises && (
-        <ExerciseComposition exercises={block.exercises} duration={duration} />
-      )}
+      {block.blocks && block.blocks.map((block) => <TrainingBlock block={block} />)}
+      {block.exercises && <ExerciseComposition exercises={block.exercises} duration={duration} />}
 
       <style jsx>
         {`
@@ -25,6 +23,6 @@ const TrainingBlock = ({ block }: { block: IBlock }) => {
         `}
       </style>
     </div>
-  );
-};
-export default TrainingBlock;
+  )
+}
+export default TrainingBlock

+ 22 - 0
frontend/src/training/components/TrainingHint.tsx

@@ -0,0 +1,22 @@
+import { FunctionComponent } from 'react'
+import { ITraining } from '../types'
+import Link from 'next/link'
+
+const TrainingHint: FunctionComponent<{ training: ITraining; index: number }> = ({
+  training,
+  index,
+}) => {
+  return (
+    <Link href='/[id]' as={`/${index}`}>
+      <a>
+        <li>
+          <div>{training.title}</div>
+          <div>{new Date(training.trainingDate).toLocaleString()}</div>
+          <style jsx>{``}</style>
+        </li>
+      </a>
+    </Link>
+  )
+}
+
+export default TrainingHint

+ 232 - 43
frontend/src/training/training.graphql

@@ -1,59 +1,248 @@
-query Trainings {
-  trainings {
+# import * from '../../../backend/database/generated/prisma.graphql'
+
+# Only some basic data to be able to display the training
+query publishedTrainings(
+  $where: TrainingWhereInput
+  $orderBy: TrainingOrderByInput
+  $skip: Int
+  $first: Int
+) {
+  publishedTrainings(where: $where, orderBy: $orderBy, skip: $skip, first: $first) {
     id
-    published
     title
     type {
       id
       name
       description
     }
-    content {
+    trainingDate
+    attendance
+    registrations {
       id
-      sequence
-      title
-      duration
-      variation
-      format {
-        id
-        name
-        description
-      }
-      tracks {
-        id
-        title
-        artist
-        duration
-        link
-      }
-      exercises {
-        id
-        name
-        description
-        video
-        targets
-        baseExercise {
-          id
-          name
+    }
+  }
+  count: trainingsCount(where: $where) {
+    aggregate {
+      count
+    }
+  }
+}
+
+# The full data set, single item.
+query training($id: ID) {
+  training(id: $id) {
+    ...displayTraining
+  }
+}
+
+# The full data set.
+query trainings(
+  $where: TrainingWhereInput
+  $orderBy: TrainingOrderByInput
+  $skip: Int
+  $after: String
+  $before: String
+  $first: Int
+  $last: Int
+) {
+  count: trainingsCount(where: $where) {
+    aggregate {
+      count
+    }
+  }
+  trainings(
+    where: $where
+    orderBy: $orderBy
+    skip: $skip
+    after: $after
+    before: $before
+    first: $first
+    last: $last
+  ) {
+    ...displayTraining
+  }
+}
+
+query trainingTypes {
+  trainingTypes {
+    id
+    name
+    description
+  }
+}
+
+query formats {
+  formats {
+    id
+    name
+    description
+  }
+}
+
+query blocks {
+  blocks {
+    ...blockWithoutBlocks
+    blocks {
+      ...blockInstanceWithoutBlock
+      block {
+        ...blockWithoutBlocks
+        blocks {
+          ...blockInstanceWithoutBlock
+          block {
+            ...blockWithoutBlocks
+          }
         }
       }
-      description
     }
-    createdAt
-    trainingDate
-    location
-    registration {
-      id
-      name
+  }
+}
+
+query exercises {
+  exercises {
+    ...exerciseContent
+  }
+}
+
+mutation createTraining(
+  $title: String!
+  $type: TrainingTypeCreateOneInput!
+  $trainingDate: DateTime!
+  $location: String!
+  $attendance: Int!
+  $published: Boolean!
+  $blocks: BlockInstanceCreateManyWithoutParentTrainingInput
+) {
+  createTraining(
+    title: $title
+    type: $type
+    trainingDate: $trainingDate
+    location: $location
+    attendance: $attendance
+    published: $published
+    blocks: $blocks
+  ) {
+    id
+  }
+}
+
+mutation updateTraining($where: TrainingWhereUniqueInput!, $data: TrainingUpdateInput!) {
+  updateTraining(where: $where, data: $data) {
+    id
+  }
+}
+
+mutation createTrainingType($name: String!, $description: String!) {
+  createTrainingType(name: $name, description: $description) {
+    id
+  }
+}
+
+mutation createFormat($name: String!, $description: String!) {
+  createFormat(name: $name, description: $description) {
+    id
+  }
+}
+
+mutation register($training: ID!) {
+  register(training: $training) {
+    id
+  }
+}
+
+mutation deregister($training: ID!) {
+  deregister(training: $training) {
+    id
+  }
+}
+
+mutation publish($training: ID!, $status: Boolean) {
+  publish(training: $training, status: $status) {
+    id
+  }
+}
+
+fragment exerciseContent on Exercise {
+  id
+  name
+  description
+  videos
+  pictures
+  targets
+  baseExercise
+}
+
+fragment blockWithoutBlocks on Block {
+  id
+  title
+  description
+  videos
+  pictures
+  duration
+  format {
+    id
+    name
+    description
+  }
+  rest
+  exercises {
+    id
+    exercise {
+      ...exerciseContent
     }
-    attendance
-    ratings {
-      user {
-        id
-        name
+    order
+    repetitions
+    variation
+  }
+}
+
+fragment blockInstanceWithoutBlock on BlockInstance {
+  id
+  order
+  rounds
+  variation
+}
+
+fragment displayTraining on Training {
+  id
+  title
+  type {
+    id
+    name
+    description
+  }
+  createdAt
+  trainingDate
+  location
+  attendance
+  published
+  blocks {
+    ...blockInstanceWithoutBlock
+    block {
+      ...blockWithoutBlocks
+      blocks {
+        ...blockInstanceWithoutBlock
+        block {
+          ...blockWithoutBlocks
+          blocks {
+            ...blockInstanceWithoutBlock
+            block {
+              ...blockWithoutBlocks
+              blocks {
+                ...blockInstanceWithoutBlock
+                block {
+                  ...blockWithoutBlocks
+                  blocks {
+                    id
+                  }
+                }
+              }
+            }
+          }
+        }
       }
-      value
-      comment
     }
   }
+  registrations {
+    id
+  }
 }

+ 87 - 37
frontend/src/training/types.ts

@@ -1,52 +1,102 @@
+import {
+  Training,
+  Block,
+  Exercise,
+  BlockInstance,
+  ExerciseInstance,
+} from "../gql";
+
 export interface ITraining {
-  id: string
-  title: string
+  id: string;
+  title: string;
   type: {
-    id: string
-    name: string
-    description: string
-  }
-  createdAt: string
-  trainingDate: string
-  location: string
-  registrations: string[]
-  attendance: number
-  ratings: IRating[]
-  published: boolean
-  blocks: IBlock[]
+    id: string;
+    name: string;
+    description: string;
+  };
+  createdAt: string;
+  trainingDate: string;
+  location: string;
+  registrations: string[];
+  attendance: number;
+  ratings: IRating[];
+  published: boolean;
+  blocks: IBlock[];
 }
 
 export interface IBlock {
-  id: string
-  sequence?: number
-  title?: string
-  comment?: string
-  description?: string
-  duration?: number
-  repetitions?: number
-  rest?: number
-  format?: IFormat
-  blocks?: IBlock[]
-  exercises?: IExercise[]
-  video?: string
+  id: string;
+  sequence?: number;
+  title?: string;
+  comment?: string;
+  description?: string;
+  duration?: number;
+  repetitions?: number;
+  rest?: number;
+  format?: IFormat;
+  blocks?: IBlock[];
+  exercises?: IExercise[];
+  video?: string;
 }
 
 export interface IFormat {}
 
 export interface IExercise {
-  id: string
-  name: string
-  description: string
-  repetitions: number
-  videos: string[]
-  pictures: string[]
-  targets: string[]
+  id: string;
+  name: string;
+  description: string;
+  repetitions: number;
+  videos: string[];
+  pictures: string[];
+  targets: string[];
   baseExercise: {
-    id: string
-    name: string
-  }
+    id: string;
+    name: string;
+  };
 }
 
 export interface IRating {
-  value: number
+  value: number;
 }
+
+export type TTraining = Pick<Training, "id" | "type"> &
+  Partial<Omit<Training, "id" | "type">>;
+export type TBlockInstance = Pick<BlockInstance, "id" | "block" | "order"> &
+  Partial<Omit<BlockInstance, "id" | "block" | "order">>;
+export type TBlock = Pick<
+  Block,
+  | "id"
+  | "title"
+  | "exercises"
+  | "videos"
+  | "blocks"
+  | "tracks"
+  | "pictures"
+  | "format"
+> &
+  Partial<
+    Omit<
+      Block,
+      | "id"
+      | "title"
+      | "exercises"
+      | "videos"
+      | "blocks"
+      | "tracks"
+      | "pictures"
+      | "format"
+    >
+  >;
+export type TExerciseInstance = Pick<ExerciseInstance, "id" | "exercise"> &
+  Partial<Omit<ExerciseInstance, "id" | "exercise">>;
+export type TExercise = Pick<
+  Exercise,
+  "id" | "name" | "pictures" | "videos" | "targets" | "baseExercise"
+> &
+  Partial<
+    Omit<
+      Exercise,
+      "id" | "name" | "pictures" | "videos" | "targets" | "baseExercise"
+    >
+  >;
+export type TRating = { value: number };

+ 3 - 3
frontend/src/user/user.graphql

@@ -9,7 +9,7 @@ query Users {
 }
 
 mutation UserSignup($email: String!, $password: String!, $name: String!) {
-  signup(email: $email, password: $password, name: $name) {
+  userSignup(email: $email, password: $password, name: $name) {
     id
     email
     name
@@ -17,7 +17,7 @@ mutation UserSignup($email: String!, $password: String!, $name: String!) {
 }
 
 mutation UserLogin($email: String!, $password: String!) {
-  login(email: $email, password: $password) {
+  userLogin(email: $email, password: $password) {
     id
     email
     name
@@ -25,7 +25,7 @@ mutation UserLogin($email: String!, $password: String!) {
 }
 
 mutation UserLogout {
-  logout
+  userLogout
 }
 
 query CurrentUser {

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません