feat: exercices, workouts and joins for admin panel
This commit is contained in:
parent
880694da19
commit
eb2737fd5e
1215
package-lock.json
generated
1215
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
26
package.json
26
package.json
@ -19,19 +19,19 @@
|
||||
"start": "cross-env NODE_OPTIONS=--no-deprecation next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@payloadcms/admin-bar": "3.33.0",
|
||||
"@payloadcms/db-postgres": "3.33.0",
|
||||
"@payloadcms/live-preview-react": "3.33.0",
|
||||
"@payloadcms/next": "3.33.0",
|
||||
"@payloadcms/payload-cloud": "3.33.0",
|
||||
"@payloadcms/plugin-form-builder": "3.33.0",
|
||||
"@payloadcms/plugin-multi-tenant": "^3.37.0",
|
||||
"@payloadcms/plugin-nested-docs": "3.33.0",
|
||||
"@payloadcms/plugin-redirects": "3.33.0",
|
||||
"@payloadcms/plugin-search": "3.33.0",
|
||||
"@payloadcms/plugin-seo": "3.33.0",
|
||||
"@payloadcms/richtext-lexical": "3.33.0",
|
||||
"@payloadcms/ui": "3.33.0",
|
||||
"@payloadcms/admin-bar": "3.38.0",
|
||||
"@payloadcms/db-postgres": "3.38.0",
|
||||
"@payloadcms/live-preview-react": "3.38.0",
|
||||
"@payloadcms/next": "3.38.0",
|
||||
"@payloadcms/payload-cloud": "3.38.0",
|
||||
"@payloadcms/plugin-form-builder": "3.38.0",
|
||||
"@payloadcms/plugin-multi-tenant": "3.38.0",
|
||||
"@payloadcms/plugin-nested-docs": "3.38.0",
|
||||
"@payloadcms/plugin-redirects": "3.38.0",
|
||||
"@payloadcms/plugin-search": "3.38.0",
|
||||
"@payloadcms/plugin-seo": "3.38.0",
|
||||
"@payloadcms/richtext-lexical": "3.38.0",
|
||||
"@payloadcms/ui": "3.38.0",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-label": "^2.0.2",
|
||||
"@radix-ui/react-select": "^2.0.0",
|
||||
|
@ -1,8 +1,5 @@
|
||||
import type { Metadata } from 'next'
|
||||
|
||||
import { cn } from '@/utilities/ui'
|
||||
import { GeistMono } from 'geist/font/mono'
|
||||
import { GeistSans } from 'geist/font/sans'
|
||||
import React from 'react'
|
||||
|
||||
import { AdminBar } from '@/components/AdminBar'
|
||||
@ -20,7 +17,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
|
||||
const { isEnabled } = await draftMode()
|
||||
|
||||
return (
|
||||
<html className={cn(GeistSans.variable, GeistMono.variable)} lang="en" suppressHydrationWarning>
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head>
|
||||
<InitTheme />
|
||||
<link href="/favicon.ico" rel="icon" sizes="32x32" />
|
||||
|
@ -18,6 +18,7 @@ import { PreviewComponent as PreviewComponent_a8a977ebc872c5d5ea7ee689724c0860 }
|
||||
import { SlugComponent as SlugComponent_92cc057d0a2abb4f6cf0307edf59f986 } from '@/fields/slug/SlugComponent'
|
||||
import { HorizontalRuleFeatureClient as HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { BlocksFeatureClient as BlocksFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client'
|
||||
import { WatchTenantCollection as WatchTenantCollection_1d0591e3cf4f332c83a86da13a0de59a } from '@payloadcms/plugin-multi-tenant/client'
|
||||
import { LinkToDoc as LinkToDoc_aead06e4cbf6b2620c5c51c9ab283634 } from '@payloadcms/plugin-search/client'
|
||||
import { ReindexButton as ReindexButton_aead06e4cbf6b2620c5c51c9ab283634 } from '@payloadcms/plugin-search/client'
|
||||
import { RowLabel as RowLabel_ec255a65fa6fa8d1faeb09cf35284224 } from '@/Header/RowLabel'
|
||||
@ -48,6 +49,7 @@ export const importMap = {
|
||||
"@/fields/slug/SlugComponent#SlugComponent": SlugComponent_92cc057d0a2abb4f6cf0307edf59f986,
|
||||
"@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient": HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/richtext-lexical/client#BlocksFeatureClient": BlocksFeatureClient_e70f5e05f09f93e00b997edb1ef0c864,
|
||||
"@payloadcms/plugin-multi-tenant/client#WatchTenantCollection": WatchTenantCollection_1d0591e3cf4f332c83a86da13a0de59a,
|
||||
"@payloadcms/plugin-search/client#LinkToDoc": LinkToDoc_aead06e4cbf6b2620c5c51c9ab283634,
|
||||
"@payloadcms/plugin-search/client#ReindexButton": ReindexButton_aead06e4cbf6b2620c5c51c9ab283634,
|
||||
"@/Header/RowLabel#RowLabel": RowLabel_ec255a65fa6fa8d1faeb09cf35284224,
|
||||
|
111
src/collections/Exercises/index.ts
Normal file
111
src/collections/Exercises/index.ts
Normal file
@ -0,0 +1,111 @@
|
||||
import { CollectionConfig } from "payload";
|
||||
|
||||
export const ExerciseTypes: CollectionConfig = {
|
||||
slug: 'exerciseTypes',
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
unique: true,
|
||||
admin: {
|
||||
description: 'Strength, Cardio, etc...',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'textarea',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const MuscleGroups: CollectionConfig = {
|
||||
slug: 'muscleGroups',
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
unique: true,
|
||||
admin: {
|
||||
description: 'Legs, Chest, or more specific...',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const Equipments: CollectionConfig = {
|
||||
slug: 'equipments',
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
unique: true,
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'textarea',
|
||||
},
|
||||
{
|
||||
name: 'warning',
|
||||
type: 'textarea',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const Exercises: CollectionConfig = {
|
||||
slug: 'exercises',
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
unique: true,
|
||||
},
|
||||
{
|
||||
name: 'type',
|
||||
type: 'relationship',
|
||||
relationTo: 'exerciseTypes',
|
||||
hasMany: true,
|
||||
},
|
||||
{
|
||||
name: 'muscleGroup',
|
||||
type: 'relationship',
|
||||
relationTo: 'muscleGroups',
|
||||
hasMany: true,
|
||||
},
|
||||
{
|
||||
name: 'equipmentNeeded',
|
||||
type: 'relationship',
|
||||
relationTo: 'equipments',
|
||||
hasMany: true,
|
||||
},
|
||||
{
|
||||
name: 'difficulty',
|
||||
type: 'number',
|
||||
max: 10,
|
||||
},
|
||||
{
|
||||
name: 'instructions',
|
||||
type: 'richText',
|
||||
},
|
||||
{
|
||||
name: 'displayImage',
|
||||
type: 'relationship',
|
||||
relationTo: 'media'
|
||||
},
|
||||
],
|
||||
}
|
102
src/collections/Workouts/index.ts
Normal file
102
src/collections/Workouts/index.ts
Normal file
@ -0,0 +1,102 @@
|
||||
import { CollectionConfig, Field } from "payload";
|
||||
|
||||
const WorkoutExercices: Field[] = [
|
||||
{
|
||||
type: 'row',
|
||||
fields: [
|
||||
{
|
||||
name: 'exercise',
|
||||
type: 'relationship',
|
||||
relationTo: 'exercises',
|
||||
hasMany: false,
|
||||
admin: {
|
||||
width: '25%',
|
||||
},
|
||||
|
||||
},
|
||||
{
|
||||
name: 'reps',
|
||||
type: 'number',
|
||||
min: 1,
|
||||
admin: {
|
||||
width: '25%',
|
||||
},
|
||||
|
||||
},
|
||||
{
|
||||
name: 'sets',
|
||||
type: 'number',
|
||||
min: 1,
|
||||
admin: {
|
||||
width: '25%',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'restMinutesAfterSet',
|
||||
type: 'number',
|
||||
admin: {
|
||||
width: '25%',
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
export const WorkoutTypes: CollectionConfig = {
|
||||
slug: 'workoutTypes',
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
unique: true,
|
||||
admin: {
|
||||
description: 'Strength, Cardio, etc...',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'textarea',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const Workouts: CollectionConfig = {
|
||||
slug: 'workouts',
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
unique: true,
|
||||
},
|
||||
{
|
||||
name: 'type',
|
||||
type: 'relationship',
|
||||
relationTo: 'workoutTypes',
|
||||
hasMany: true,
|
||||
},
|
||||
{
|
||||
name: 'difficulty',
|
||||
type: 'number',
|
||||
max: 10,
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'textarea',
|
||||
},
|
||||
{
|
||||
name: 'durationMinutes',
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
name: 'exercises',
|
||||
type: 'array',
|
||||
fields: WorkoutExercices
|
||||
}
|
||||
],
|
||||
}
|
@ -73,6 +73,12 @@ export interface Config {
|
||||
categories: Category;
|
||||
users: User;
|
||||
tenants: Tenant;
|
||||
exercises: Exercise;
|
||||
exerciseTypes: ExerciseType;
|
||||
muscleGroups: MuscleGroup;
|
||||
equipments: Equipment;
|
||||
workouts: Workout;
|
||||
workoutTypes: WorkoutType;
|
||||
redirects: Redirect;
|
||||
forms: Form;
|
||||
'form-submissions': FormSubmission;
|
||||
@ -90,6 +96,12 @@ export interface Config {
|
||||
categories: CategoriesSelect<false> | CategoriesSelect<true>;
|
||||
users: UsersSelect<false> | UsersSelect<true>;
|
||||
tenants: TenantsSelect<false> | TenantsSelect<true>;
|
||||
exercises: ExercisesSelect<false> | ExercisesSelect<true>;
|
||||
exerciseTypes: ExerciseTypesSelect<false> | ExerciseTypesSelect<true>;
|
||||
muscleGroups: MuscleGroupsSelect<false> | MuscleGroupsSelect<true>;
|
||||
equipments: EquipmentsSelect<false> | EquipmentsSelect<true>;
|
||||
workouts: WorkoutsSelect<false> | WorkoutsSelect<true>;
|
||||
workoutTypes: WorkoutTypesSelect<false> | WorkoutTypesSelect<true>;
|
||||
redirects: RedirectsSelect<false> | RedirectsSelect<true>;
|
||||
forms: FormsSelect<false> | FormsSelect<true>;
|
||||
'form-submissions': FormSubmissionsSelect<false> | FormSubmissionsSelect<true>;
|
||||
@ -761,6 +773,119 @@ export interface Form {
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "exercises".
|
||||
*/
|
||||
export interface Exercise {
|
||||
id: number;
|
||||
tenant?: (number | null) | Tenant;
|
||||
name?: string | null;
|
||||
type?: (number | ExerciseType)[] | null;
|
||||
muscleGroup?: (number | MuscleGroup)[] | null;
|
||||
equipmentNeeded?: (number | Equipment)[] | null;
|
||||
difficulty?: number | null;
|
||||
instructions?: {
|
||||
root: {
|
||||
type: string;
|
||||
children: {
|
||||
type: string;
|
||||
version: number;
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
direction: ('ltr' | 'rtl') | null;
|
||||
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||
indent: number;
|
||||
version: number;
|
||||
};
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
displayImage?: (number | null) | Media;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "exerciseTypes".
|
||||
*/
|
||||
export interface ExerciseType {
|
||||
id: number;
|
||||
tenant?: (number | null) | Tenant;
|
||||
/**
|
||||
* Strength, Cardio, etc...
|
||||
*/
|
||||
name?: string | null;
|
||||
description?: string | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "muscleGroups".
|
||||
*/
|
||||
export interface MuscleGroup {
|
||||
id: number;
|
||||
tenant?: (number | null) | Tenant;
|
||||
/**
|
||||
* Legs, Chest, or more specific...
|
||||
*/
|
||||
name?: string | null;
|
||||
description?: string | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "equipments".
|
||||
*/
|
||||
export interface Equipment {
|
||||
id: number;
|
||||
tenant?: (number | null) | Tenant;
|
||||
name?: string | null;
|
||||
description?: string | null;
|
||||
warning?: string | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "workouts".
|
||||
*/
|
||||
export interface Workout {
|
||||
id: number;
|
||||
tenant?: (number | null) | Tenant;
|
||||
name?: string | null;
|
||||
type?: (number | WorkoutType)[] | null;
|
||||
difficulty?: number | null;
|
||||
description?: string | null;
|
||||
durationMinutes?: number | null;
|
||||
exercises?:
|
||||
| {
|
||||
exercise?: (number | null) | Exercise;
|
||||
reps?: number | null;
|
||||
sets?: number | null;
|
||||
restMinutesAfterSet?: number | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "workoutTypes".
|
||||
*/
|
||||
export interface WorkoutType {
|
||||
id: number;
|
||||
tenant?: (number | null) | Tenant;
|
||||
/**
|
||||
* Strength, Cardio, etc...
|
||||
*/
|
||||
name?: string | null;
|
||||
description?: string | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "redirects".
|
||||
@ -957,6 +1082,30 @@ export interface PayloadLockedDocument {
|
||||
relationTo: 'tenants';
|
||||
value: number | Tenant;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'exercises';
|
||||
value: number | Exercise;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'exerciseTypes';
|
||||
value: number | ExerciseType;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'muscleGroups';
|
||||
value: number | MuscleGroup;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'equipments';
|
||||
value: number | Equipment;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'workouts';
|
||||
value: number | Workout;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'workoutTypes';
|
||||
value: number | WorkoutType;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'redirects';
|
||||
value: number | Redirect;
|
||||
@ -1336,6 +1485,90 @@ export interface TenantsSelect<T extends boolean = true> {
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "exercises_select".
|
||||
*/
|
||||
export interface ExercisesSelect<T extends boolean = true> {
|
||||
tenant?: T;
|
||||
name?: T;
|
||||
type?: T;
|
||||
muscleGroup?: T;
|
||||
equipmentNeeded?: T;
|
||||
difficulty?: T;
|
||||
instructions?: T;
|
||||
displayImage?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "exerciseTypes_select".
|
||||
*/
|
||||
export interface ExerciseTypesSelect<T extends boolean = true> {
|
||||
tenant?: T;
|
||||
name?: T;
|
||||
description?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "muscleGroups_select".
|
||||
*/
|
||||
export interface MuscleGroupsSelect<T extends boolean = true> {
|
||||
tenant?: T;
|
||||
name?: T;
|
||||
description?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "equipments_select".
|
||||
*/
|
||||
export interface EquipmentsSelect<T extends boolean = true> {
|
||||
tenant?: T;
|
||||
name?: T;
|
||||
description?: T;
|
||||
warning?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "workouts_select".
|
||||
*/
|
||||
export interface WorkoutsSelect<T extends boolean = true> {
|
||||
tenant?: T;
|
||||
name?: T;
|
||||
type?: T;
|
||||
difficulty?: T;
|
||||
description?: T;
|
||||
durationMinutes?: T;
|
||||
exercises?:
|
||||
| T
|
||||
| {
|
||||
exercise?: T;
|
||||
reps?: T;
|
||||
sets?: T;
|
||||
restMinutesAfterSet?: T;
|
||||
id?: T;
|
||||
};
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "workoutTypes_select".
|
||||
*/
|
||||
export interface WorkoutTypesSelect<T extends boolean = true> {
|
||||
tenant?: T;
|
||||
name?: T;
|
||||
description?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "redirects_select".
|
||||
|
@ -17,6 +17,8 @@ import { plugins } from './plugins'
|
||||
import { defaultLexical } from '@/fields/defaultLexical'
|
||||
import { getServerSideURL } from './utilities/getURL'
|
||||
import { Tenants } from './collections/Tenants'
|
||||
import { Equipments, Exercises, ExerciseTypes, MuscleGroups } from './collections/Exercises'
|
||||
import { Workouts, WorkoutTypes } from './collections/Workouts'
|
||||
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
@ -65,7 +67,7 @@ export default buildConfig({
|
||||
connectionString: process.env.DATABASE_URI || '',
|
||||
},
|
||||
}),
|
||||
collections: [Pages, Posts, Media, Categories, Users, Tenants],
|
||||
collections: [Pages, Posts, Media, Categories, Users, Tenants, Exercises, ExerciseTypes, MuscleGroups, Equipments, Workouts, WorkoutTypes],
|
||||
cors: [getServerSideURL()].filter(Boolean),
|
||||
globals: [Header, Footer],
|
||||
plugins: [
|
||||
|
@ -98,10 +98,13 @@ export const plugins: Plugin[] = [
|
||||
debug: true,
|
||||
enabled: true,
|
||||
collections: {
|
||||
pages: {
|
||||
useBaseListFilter: true,
|
||||
useTenantAccess: true,
|
||||
},
|
||||
pages: {},
|
||||
exercises: {},
|
||||
exerciseTypes: {},
|
||||
muscleGroups: {},
|
||||
equipments: {},
|
||||
workouts: {},
|
||||
workoutTypes: {},
|
||||
},
|
||||
tenantsArrayField: {
|
||||
includeDefaultField: false,
|
||||
|
Loading…
x
Reference in New Issue
Block a user