diff --git a/drizzle.config.ts b/drizzle.config.ts index e85917ac..c246563e 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -3,7 +3,8 @@ import type { Config } from "drizzle-kit"; export default { schema: "./src/db/schema.ts", dbCredentials: { - connectionString: process.env.DB_URL!, + connectionString: "postgres://postgres:postgres@localhost:5432/gym-graphs", }, out: "./drizzle", + driver: "pg", } satisfies Config; diff --git a/drizzle/0025_gifted_silver_surfer.sql b/drizzle/0025_gifted_silver_surfer.sql new file mode 100644 index 00000000..edfe937c --- /dev/null +++ b/drizzle/0025_gifted_silver_surfer.sql @@ -0,0 +1 @@ +ALTER TABLE "exercise" ALTER COLUMN "muscle_groups" SET DEFAULT []; \ No newline at end of file diff --git a/drizzle/0026_hard_orphan.sql b/drizzle/0026_hard_orphan.sql new file mode 100644 index 00000000..2ae86ae5 --- /dev/null +++ b/drizzle/0026_hard_orphan.sql @@ -0,0 +1 @@ +ALTER TABLE "exercise" ALTER COLUMN "muscle_groups" SET DEFAULT {}; \ No newline at end of file diff --git a/drizzle/0027_sloppy_firebrand.sql b/drizzle/0027_sloppy_firebrand.sql new file mode 100644 index 00000000..ff7791f9 --- /dev/null +++ b/drizzle/0027_sloppy_firebrand.sql @@ -0,0 +1 @@ +ALTER TABLE "exercise" ALTER COLUMN "muscle_groups" SET DEFAULT '{}'; \ No newline at end of file diff --git a/drizzle/meta/0025_snapshot.json b/drizzle/meta/0025_snapshot.json new file mode 100644 index 00000000..d0503b48 --- /dev/null +++ b/drizzle/meta/0025_snapshot.json @@ -0,0 +1,460 @@ +{ + "version": "5", + "dialect": "pg", + "id": "81cdace0-e33a-465a-b3f0-3559093b29a7", + "prevId": "685d708f-336c-4a19-a7b1-ca11083a3f0f", + "tables": { + "account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId": { + "name": "account_provider_providerAccountId", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "exercise_grid_position": { + "name": "exercise_grid_position", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "exercise_id": { + "name": "exercise_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "grid_position": { + "name": "grid_position", + "type": "serial", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "exercise_grid_position_exercise_id_exercise_id_fk": { + "name": "exercise_grid_position_exercise_id_exercise_id_fk", + "tableFrom": "exercise_grid_position", + "tableTo": "exercise", + "columnsFrom": [ + "exercise_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "exercise_grid_position_user_id_user_id_fk": { + "name": "exercise_grid_position_user_id_user_id_fk", + "tableFrom": "exercise_grid_position", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "exercise": { + "name": "exercise", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "muscle_groups": { + "name": "muscle_groups", + "type": "muscle_groups[]", + "primaryKey": false, + "notNull": true, + "default": "[]" + } + }, + "indexes": {}, + "foreignKeys": { + "exercise_user_id_user_id_fk": { + "name": "exercise_user_id_user_id_fk", + "tableFrom": "exercise", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "exercise_user_id_name_unique": { + "name": "exercise_user_id_name_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "name" + ] + } + } + }, + "exercise_data": { + "name": "exercise_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "exercise_id": { + "name": "exercise_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "number_of_repetitions": { + "name": "number_of_repetitions", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "weight_lifted": { + "name": "weight_lifted", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "done_at": { + "name": "done_at", + "type": "date", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "exercise_data_exercise_id_exercise_id_fk": { + "name": "exercise_data_exercise_id_exercise_id_fk", + "tableFrom": "exercise_data", + "tableTo": "exercise", + "columnsFrom": [ + "exercise_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "exercise_data_done_at_exercise_id_unique": { + "name": "exercise_data_done_at_exercise_id_unique", + "nullsNotDistinct": false, + "columns": [ + "done_at", + "exercise_id" + ] + } + } + }, + "session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token": { + "name": "verificationToken_identifier_token", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + } + }, + "enums": { + "muscle_groups": { + "name": "muscle_groups", + "values": { + "legs": "legs", + "chest": "chest", + "biceps": "biceps", + "triceps": "triceps", + "back": "back", + "shoulders": "shoulders", + "calfs": "calfs", + "abs": "abs", + "traps": "traps" + } + } + }, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/0026_snapshot.json b/drizzle/meta/0026_snapshot.json new file mode 100644 index 00000000..38d2b1cc --- /dev/null +++ b/drizzle/meta/0026_snapshot.json @@ -0,0 +1,460 @@ +{ + "version": "5", + "dialect": "pg", + "id": "51563ec3-f36e-43b8-a180-cf741a2360d9", + "prevId": "81cdace0-e33a-465a-b3f0-3559093b29a7", + "tables": { + "account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId": { + "name": "account_provider_providerAccountId", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "exercise_grid_position": { + "name": "exercise_grid_position", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "exercise_id": { + "name": "exercise_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "grid_position": { + "name": "grid_position", + "type": "serial", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "exercise_grid_position_exercise_id_exercise_id_fk": { + "name": "exercise_grid_position_exercise_id_exercise_id_fk", + "tableFrom": "exercise_grid_position", + "tableTo": "exercise", + "columnsFrom": [ + "exercise_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "exercise_grid_position_user_id_user_id_fk": { + "name": "exercise_grid_position_user_id_user_id_fk", + "tableFrom": "exercise_grid_position", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "exercise": { + "name": "exercise", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "muscle_groups": { + "name": "muscle_groups", + "type": "muscle_groups[]", + "primaryKey": false, + "notNull": true, + "default": "{}" + } + }, + "indexes": {}, + "foreignKeys": { + "exercise_user_id_user_id_fk": { + "name": "exercise_user_id_user_id_fk", + "tableFrom": "exercise", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "exercise_user_id_name_unique": { + "name": "exercise_user_id_name_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "name" + ] + } + } + }, + "exercise_data": { + "name": "exercise_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "exercise_id": { + "name": "exercise_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "number_of_repetitions": { + "name": "number_of_repetitions", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "weight_lifted": { + "name": "weight_lifted", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "done_at": { + "name": "done_at", + "type": "date", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "exercise_data_exercise_id_exercise_id_fk": { + "name": "exercise_data_exercise_id_exercise_id_fk", + "tableFrom": "exercise_data", + "tableTo": "exercise", + "columnsFrom": [ + "exercise_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "exercise_data_done_at_exercise_id_unique": { + "name": "exercise_data_done_at_exercise_id_unique", + "nullsNotDistinct": false, + "columns": [ + "done_at", + "exercise_id" + ] + } + } + }, + "session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token": { + "name": "verificationToken_identifier_token", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + } + }, + "enums": { + "muscle_groups": { + "name": "muscle_groups", + "values": { + "legs": "legs", + "chest": "chest", + "biceps": "biceps", + "triceps": "triceps", + "back": "back", + "shoulders": "shoulders", + "calfs": "calfs", + "abs": "abs", + "traps": "traps" + } + } + }, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/0027_snapshot.json b/drizzle/meta/0027_snapshot.json new file mode 100644 index 00000000..f5df9ff3 --- /dev/null +++ b/drizzle/meta/0027_snapshot.json @@ -0,0 +1,460 @@ +{ + "version": "5", + "dialect": "pg", + "id": "49ffbdb0-e141-46ad-bcd3-b4137af3470c", + "prevId": "51563ec3-f36e-43b8-a180-cf741a2360d9", + "tables": { + "account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId": { + "name": "account_provider_providerAccountId", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "exercise_grid_position": { + "name": "exercise_grid_position", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "exercise_id": { + "name": "exercise_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "grid_position": { + "name": "grid_position", + "type": "serial", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "exercise_grid_position_exercise_id_exercise_id_fk": { + "name": "exercise_grid_position_exercise_id_exercise_id_fk", + "tableFrom": "exercise_grid_position", + "tableTo": "exercise", + "columnsFrom": [ + "exercise_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "exercise_grid_position_user_id_user_id_fk": { + "name": "exercise_grid_position_user_id_user_id_fk", + "tableFrom": "exercise_grid_position", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "exercise": { + "name": "exercise", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "muscle_groups": { + "name": "muscle_groups", + "type": "muscle_groups[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + } + }, + "indexes": {}, + "foreignKeys": { + "exercise_user_id_user_id_fk": { + "name": "exercise_user_id_user_id_fk", + "tableFrom": "exercise", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "exercise_user_id_name_unique": { + "name": "exercise_user_id_name_unique", + "nullsNotDistinct": false, + "columns": [ + "user_id", + "name" + ] + } + } + }, + "exercise_data": { + "name": "exercise_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "exercise_id": { + "name": "exercise_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "number_of_repetitions": { + "name": "number_of_repetitions", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "weight_lifted": { + "name": "weight_lifted", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "done_at": { + "name": "done_at", + "type": "date", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "exercise_data_exercise_id_exercise_id_fk": { + "name": "exercise_data_exercise_id_exercise_id_fk", + "tableFrom": "exercise_data", + "tableTo": "exercise", + "columnsFrom": [ + "exercise_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "exercise_data_done_at_exercise_id_unique": { + "name": "exercise_data_done_at_exercise_id_unique", + "nullsNotDistinct": false, + "columns": [ + "done_at", + "exercise_id" + ] + } + } + }, + "session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token": { + "name": "verificationToken_identifier_token", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + } + }, + "enums": { + "muscle_groups": { + "name": "muscle_groups", + "values": { + "legs": "legs", + "chest": "chest", + "biceps": "biceps", + "triceps": "triceps", + "back": "back", + "shoulders": "shoulders", + "calfs": "calfs", + "abs": "abs", + "traps": "traps" + } + } + }, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index b17082c7..776a4be0 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -176,6 +176,27 @@ "when": 1696585145282, "tag": "0024_lowly_blazing_skull", "breakpoints": true + }, + { + "idx": 25, + "version": "5", + "when": 1716402185228, + "tag": "0025_gifted_silver_surfer", + "breakpoints": true + }, + { + "idx": 26, + "version": "5", + "when": 1716402203597, + "tag": "0026_hard_orphan", + "breakpoints": true + }, + { + "idx": 27, + "version": "5", + "when": 1716402256605, + "tag": "0027_sloppy_firebrand", + "breakpoints": true } ] } \ No newline at end of file diff --git a/package.json b/package.json index 358451d2..309e55d4 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "start": "next start", "lint": "next lint", "db:generate": "drizzle-kit generate:pg", + "db:push": "drizzle-kit push:pg", "e2e:ui": "npx playwright test --ui" }, "dependencies": { diff --git a/src/app/dashboard-new/layout.tsx b/src/app/dashboard-new/layout.tsx deleted file mode 100644 index d9cbe2c6..00000000 --- a/src/app/dashboard-new/layout.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { DashboardBackground } from "@/components/ui/dashboardBackground"; -import type { ComponentPropsWithoutRef, PropsWithChildren } from "react"; - -const Layout = (props: PropsWithChildren) => { - return ( - - {props.children} - - - - - - ); -}; - -export default Layout; - -const Container = (props: ComponentPropsWithoutRef<"main">) => { - return ( -
- ); -}; - -const ContentContainer = (props: ComponentPropsWithoutRef<"div">) => { - return ( -
- ); -}; - -const BackgroundContainer = (props: ComponentPropsWithoutRef<"div">) => { - return ( -
- ); -}; diff --git a/src/app/dashboard-new/page.tsx b/src/app/dashboard-new/page.tsx deleted file mode 100644 index 1f000b84..00000000 --- a/src/app/dashboard-new/page.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { NewExerciseForm } from "./_components/newExerciseForm/newExerciseForm"; -import { getServerAuthSession } from "@/server/auth"; -import { redirect } from "next/navigation"; -import { createSSRHelper } from "@/trpc/server"; -import { HydrationBoundary, dehydrate } from "@tanstack/react-query"; -import { AllExercisesTimeline } from "./_components/allExercisesTimeline/allExercisesTimeline"; -import { MonthlyExercisesTimeline } from "./_components/monthlyExercisesTimeline/monthlyExercisesTimeline"; - -const Page = async () => { - const session = await getServerAuthSession(); - - if (!session?.user.id) { - return redirect("/"); - } - - const helpers = await createSSRHelper(); - await helpers.exercise.all.prefetch(); - - return ( - <> - - - - - - - - - - - ); -}; - -export default Page; diff --git a/src/app/dashboard/@allExercisesGrid/error.tsx b/src/app/dashboard/@allExercisesGrid/error.tsx deleted file mode 100644 index 316ce407..00000000 --- a/src/app/dashboard/@allExercisesGrid/error.tsx +++ /dev/null @@ -1,47 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import type { ComponentProps } from "react"; - -type Props = { - error: Error; - reset: () => void; -}; -const Error = (props: Props) => { - return ( -
- Something went wrong - - Sorry, we could not load all your exercises because: - - {JSON.stringify(props)} - -
- ); -}; - -export default Error; - -const ErrorTitle = (props: ComponentProps<"h2">) => { - return ( -

- ); -}; - -const ErrorSubText = (props: ComponentProps<"p">) => { - return

; -}; - -const ErrorDescription = (props: ComponentProps<"code">) => { - return ( - - ); -}; diff --git a/src/app/dashboard/@allExercisesGrid/filtersComponent.tsx b/src/app/dashboard/@allExercisesGrid/filtersComponent.tsx deleted file mode 100644 index 235fadcc..00000000 --- a/src/app/dashboard/@allExercisesGrid/filtersComponent.tsx +++ /dev/null @@ -1,184 +0,0 @@ -"use client"; - -import type { Exercise } from "@/db/types"; -import { usePathname, useRouter, useSearchParams } from "next/navigation"; -import { useState, useTransition } from "react"; -import type { ChangeEvent } from "react"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { - DropdownMenu, - DropdownMenuCheckboxItem, - DropdownMenuContent, - DropdownMenuGroup, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { Button } from "@/components/ui/button"; -import { Filter } from "lucide-react"; -import { Input } from "@/components/ui/input"; -import { Loader } from "@/components/ui/loader"; -import { muscleGroupsEnum } from "@/db/schema"; - -export const SearchFilter = () => { - const router = useRouter(); - const pathname = usePathname(); - const searchParams = useSearchParams(); - const [isPending, startTransition] = useTransition(); - const [exerciseName, setExerciseName] = useState( - searchParams.get("search") ?? "", - ); - - const updateExerciseNameUrlParams = (e: ChangeEvent) => { - const current = new URLSearchParams(Array.from(searchParams.entries())); - - if (!e.target.value) { - current.delete("search"); - } else { - current.set("search", e.target.value); - } - - const search = current.toString(); - const query = search ? `?${search}` : ""; - - startTransition(() => { - router.push(`${pathname}${query}`); - }); - }; - - return ( -

- {isPending && } - { - updateExerciseNameUrlParams(e); - setExerciseName(e.target.value); - }} - /> -
- ); -}; - -export const MuscleGroupsFilter = () => { - const router = useRouter(); - const pathname = usePathname(); - const searchParams = useSearchParams(); - const [isPending, startTransition] = useTransition(); - - const muscleGroups = searchParams.get("tags"); - const selectedValues = muscleGroups - ? (muscleGroups - .split(",") - .filter((muscleGroup) => - (muscleGroupsEnum.enumValues as string[]).includes(muscleGroup), - ) as Exercise["muscleGroups"]) - : []; - - const [lastOptionClicked, setLastOptionClicked] = useState< - Exercise["muscleGroups"][number] | null - >(null); - - const updateTagsUrlParams = (newMuscleGroups: Exercise["muscleGroups"]) => { - const current = new URLSearchParams(Array.from(searchParams.entries())); - - if (newMuscleGroups.length < 1) { - current.delete("tags"); - } else { - current.set("tags", newMuscleGroups.join(",")); - } - - const search = current.toString(); - const query = search ? `?${search}` : ""; - - startTransition(() => { - router.push(`${pathname}${query}`); - }); - }; - - return ( - - - - - - - - - -

tags

-
-
-
- - - - muscle groups - - - - - {muscleGroupsEnum.enumValues.map((muscleGroup) => { - const isSelected = selectedValues.includes(muscleGroup); - - return ( - e.preventDefault()} - disabled={isPending && lastOptionClicked === muscleGroup} - onCheckedChange={() => { - const filteredMuscleGroups = isSelected - ? selectedValues.filter((v) => v !== muscleGroup) - : [...selectedValues, muscleGroup]; - - updateTagsUrlParams(filteredMuscleGroups); - setLastOptionClicked(muscleGroup); - }} - > - {isPending && lastOptionClicked === muscleGroup && ( - - )} - {muscleGroup} - - ); - })} - - - {selectedValues.length > 0 && ( - <> - - - updateTagsUrlParams([])} - className="justify-center text-center" - > - Clear filters - - - - )} - -
- ); -}; diff --git a/src/app/dashboard/@allExercisesGrid/layout.tsx b/src/app/dashboard/@allExercisesGrid/layout.tsx deleted file mode 100644 index a576cb92..00000000 --- a/src/app/dashboard/@allExercisesGrid/layout.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import type { ComponentProps, PropsWithChildren } from "react"; -import { TimelineContainer } from "../timelineContainer"; -import { Badge } from "@/components/ui/badge"; -import { MuscleGroupsFilter, SearchFilter } from "./filtersComponent"; - -const Layout = ({ children }: PropsWithChildren) => { - return ( - - - - - - - - - - - {children} - - ); -}; - -export default Layout; - -const TimelineActionsContainer = (props: ComponentProps<"div">) => { - return
; -}; diff --git a/src/app/dashboard/@allExercisesGrid/loading.tsx b/src/app/dashboard/@allExercisesGrid/loading.tsx deleted file mode 100644 index 1dba7795..00000000 --- a/src/app/dashboard/@allExercisesGrid/loading.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { Skeleton } from "@/components/ui/skeleton"; -import { GridLayout } from "../_grid/gridLayout"; - -const Loader = () => { - return ( - - {[...Array(20)].map((_, i) => ( - -
- - ))} - - ); -}; - -export default Loader; diff --git a/src/app/dashboard/@allExercisesGrid/optimisticExerciseItem.tsx b/src/app/dashboard/@allExercisesGrid/optimisticExerciseItem.tsx deleted file mode 100644 index d42ea3ec..00000000 --- a/src/app/dashboard/@allExercisesGrid/optimisticExerciseItem.tsx +++ /dev/null @@ -1,39 +0,0 @@ -"use client"; - -import { type MutationState, useMutationState } from "@tanstack/react-query"; -import { GridItem } from "../_grid/gridItem"; -import { getQueryKey } from "@trpc/react-query"; -import { type RouterInputs, api } from "@/trpc/react"; -import { Skeleton } from "@/components/ui/skeleton"; -import { RadarGraph } from "../_graphs/radarGraph"; - -type CreateExerciseMutationState = MutationState< - unknown, - Error, - RouterInputs["exercise"]["create"] ->; - -export const OptimisticExerciseItem = () => { - const createExerciseMutations = useMutationState( - { - filters: { mutationKey: getQueryKey(api.exercise.create) }, - }, - ); - - const latestMutation = createExerciseMutations?.at(-1); - const newExerciseName = latestMutation?.variables?.name; - - if (!newExerciseName || latestMutation?.status !== "pending") { - return null; - } - - return ( - - - - {newExerciseName} - - - - ); -}; diff --git a/src/app/dashboard/@allExercisesGrid/page.tsx b/src/app/dashboard/@allExercisesGrid/page.tsx deleted file mode 100644 index 3a973eb7..00000000 --- a/src/app/dashboard/@allExercisesGrid/page.tsx +++ /dev/null @@ -1,201 +0,0 @@ -import { db } from "@/db"; -import { getServerSession } from "next-auth"; -import { authOptions } from "@/lib/auth"; -import { redirect } from "next/navigation"; -import type { ComponentProps, PropsWithChildren } from "react"; -import type { Exercise, User } from "@/db/types"; -import { GridLayout } from "../_grid/gridLayout"; -import { DragComponent, SortableGrid } from "./sortableGrid"; -import { GridItem } from "../_grid/gridItem"; -import { LineGraph } from "../_graphs/lineGraph"; -import { RadarGraph } from "../_graphs/radarGraph"; -import { MoreHorizontal, Tag } from "lucide-react"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuGroup, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { UpdateExerciseNameDialog } from "../_modals/updateExerciseNameDialog"; -import { DeleteExerciseAlertDialog } from "../_modals/deleteExerciseAlertDialog"; -import { ExerciseMuscleGroupsDropdown } from "./exerciseMuscleGroups"; -import type { DashboardPageProps } from "../getExercisesWhereClause"; -import { getExercisesWhereClause } from "../getExercisesWhereClause"; -import { RandomFacts } from "../_graphs/randomFacts"; -import { OptimisticExerciseItem } from "./optimisticExerciseItem"; - -const AllExercisesGrid = async (props: DashboardPageProps) => { - const session = await getServerSession(authOptions); - - if (!session?.user.id) { - return redirect("/"); - } - - const exercises = await getExercises(session.user.id, props.searchParams); - - if (exercises.length < 1 && props.searchParams?.search) { - return ( - - - no exercises named {props.searchParams.search}{" "} - found - - - ); - } - - if (exercises.length < 1 && props.searchParams?.tags) { - return ( - - - no exercises with the tag of{" "} - {props.searchParams.tags} found - - - ); - } - - if (exercises.length < 1 && !props.searchParams?.search) { - return ( - - - Your dashboard is empty -
- Start adding new data with the form above -
-
- ); - } - - return ( - - - - ({ - id: exercise.id, - render: ( - - - - {exercise.name} - - - - - - - - - - - - - - - - - - - - - ), - }))} - /> - - - - exercises count - - - ({ - exerciseName: exercise.name, - frequency: exercise.data.length, - }))} - /> - - - - - random facts - - - - - - ); -}; - -export default AllExercisesGrid; - -const Container = (props: ComponentProps<"div">) => { - return ( -
- ); -}; - -const Text = (props: ComponentProps<"p">) => { - return

; -}; - -const getExercises = async ( - userId: User["id"], - searchParams: DashboardPageProps["searchParams"], -) => { - return ( - await db.query.exercises.findMany({ - with: { - data: { orderBy: (data, { asc }) => [asc(data.doneAt)] }, - position: true, - }, - where: () => getExercisesWhereClause({ searchParams, userId }), - }) - ).sort((a, b) => b.position.gridPosition - a.position.gridPosition); -}; - -const ExerciseDropDown = ({ - exercise, - children, -}: { exercise: Exercise } & PropsWithChildren) => { - return ( - - - - - {children} - - -

view more

- - - - - settings - - - - - - - - ); -}; - -const PropsText = (props: ComponentProps<"span">) => { - return ; -}; diff --git a/src/app/dashboard/@allExercisesGrid/sortableGrid.tsx b/src/app/dashboard/@allExercisesGrid/sortableGrid.tsx deleted file mode 100644 index e5bbe644..00000000 --- a/src/app/dashboard/@allExercisesGrid/sortableGrid.tsx +++ /dev/null @@ -1,172 +0,0 @@ -"use client"; - -import { - useSensor, - useSensors, - DndContext, - TouchSensor, - MouseSensor, - KeyboardSensor, - closestCenter, -} from "@dnd-kit/core"; -import type { DragEndEvent } from "@dnd-kit/core"; -import { - arrayMove, - rectSortingStrategy, - SortableContext, - sortableKeyboardCoordinates, - useSortable, -} from "@dnd-kit/sortable"; -import { useEffect, useState } from "react"; -import type { PropsWithChildren, ReactNode } from "react"; -import { Slot } from "@radix-ui/react-slot"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { GripVertical } from "lucide-react"; -import { Button } from "@/components/ui/button"; -import { Loader } from "@/components/ui/loader"; -import { api } from "@/trpc/react"; -import { useMutationState } from "@tanstack/react-query"; -import { getQueryKey } from "@trpc/react-query"; -import { useToast } from "@/components/ui/use-toast"; -import { ToastAction } from "@/components/ui/toast"; - -type Props = { - gridItems: { render: ReactNode; id: string }[]; -}; - -export const SortableGrid = (props: Props) => { - const [gridItems, setGridItems] = useState(props.gridItems); - const { toast } = useToast(); - const utils = api.useUtils(); - - const moveExercise = api.exercise.move.useMutation({ - onError: (error, variables) => { - toast({ - variant: "destructive", - title: "Something went wrong", - description: error.shape?.data.zodError?.fieldErrors?.name?.at(0), - action: ( - moveExercise.mutate(variables)} - > - Try again - - ), - }); - }, - onSettled: async () => { - await utils.exercise.all.invalidate(); - }, - }); - - useEffect(() => setGridItems(props.gridItems), [props.gridItems]); - - const sensors = useSensors( - useSensor(MouseSensor), - useSensor(TouchSensor), - useSensor(KeyboardSensor, { - coordinateGetter: sortableKeyboardCoordinates, - }), - ); - - const handleDragEnd = (event: DragEndEvent) => { - const { active, over } = event; - - if (active.id === over?.id) { - return; - } - - const oldIndex = gridItems.findIndex((x) => x.id === active?.id); - const newIndex = gridItems.findIndex((x) => x.id === over?.id); - - const updatedGridItems = arrayMove(gridItems, oldIndex, newIndex); - - setGridItems(updatedGridItems); - - moveExercise.mutate(updatedGridItems.map((item) => item.id)); - }; - - return ( - void handleDragEnd(e)} - collisionDetection={closestCenter} - > - - {gridItems.map((item) => ( - - {item.render} - - ))} - - - ); -}; - -const SortableItem = (props: { id: string } & PropsWithChildren) => { - const { setNodeRef, isDragging, transform, transition } = useSortable({ - id: props.id, - }); - - return ( - - {props.children} - - ); -}; - -export const DragComponent = ({ id }: { id: string }) => { - const { attributes, listeners } = useSortable({ id }); - - const moveExerciseMutationState = useMutationState({ - filters: { - mutationKey: getQueryKey(api.exercise.move), - }, - }); - - const isSavingGridState = - moveExerciseMutationState.at(-1)?.status === "pending"; - - return ( - - - - - - -

drag exercise

-
-
-
- ); -}; diff --git a/src/app/dashboard/@exercisesByMonthGrid/error.tsx b/src/app/dashboard/@exercisesByMonthGrid/error.tsx deleted file mode 100644 index 60e1708b..00000000 --- a/src/app/dashboard/@exercisesByMonthGrid/error.tsx +++ /dev/null @@ -1,48 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { TimelineContainer } from "../timelineContainer"; -import type { ComponentProps } from "react"; - -type Props = { - error: Error; - reset: () => void; -}; -const Error = (props: Props) => { - return ( - - Something went wrong - - Sorry, we could not load your exercises by month because: - - {JSON.stringify(props)} - - - ); -}; - -export default Error; - -const ErrorTitle = (props: ComponentProps<"h2">) => { - return ( -

- ); -}; - -const ErrorSubText = (props: ComponentProps<"p">) => { - return

; -}; - -const ErrorDescription = (props: ComponentProps<"code">) => { - return ( - - ); -}; diff --git a/src/app/dashboard/@exercisesByMonthGrid/loading.tsx b/src/app/dashboard/@exercisesByMonthGrid/loading.tsx deleted file mode 100644 index 618f98b9..00000000 --- a/src/app/dashboard/@exercisesByMonthGrid/loading.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Skeleton } from "@/components/ui/skeleton"; -import { GridLayout } from "../_grid/gridLayout"; -import { TimelineContainer } from "../timelineContainer"; -import { Badge } from "@/components/ui/badge"; - -const Loader = () => { - return ( - <> - {[...Array(3)].map((_, i) => ( - - - - - - - {[...Array(10)].map((_, i) => ( - -

- - ))} - - - ))} - - ); -}; - -export default Loader; diff --git a/src/app/dashboard/@exercisesByMonthGrid/page.tsx b/src/app/dashboard/@exercisesByMonthGrid/page.tsx deleted file mode 100644 index ed53d5da..00000000 --- a/src/app/dashboard/@exercisesByMonthGrid/page.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import { db } from "@/db"; -import type { ExerciseWithData, User } from "@/db/types"; -import { getServerSession } from "next-auth"; -import { redirect } from "next/navigation"; -import { authOptions } from "@/lib/auth"; -import { dateAsYearMonthDayFormat } from "@/lib/date"; -import { TimelineContainer } from "../timelineContainer"; -import { Badge } from "@/components/ui/badge"; -import { GridLayout } from "../_grid/gridLayout"; -import { GridItem } from "../_grid/gridItem"; -import { LineGraph } from "../_graphs/lineGraph"; -import { RadarGraph } from "../_graphs/radarGraph"; -import { HeatmapGraph } from "../_graphs/heatmapGraph"; -import { prepareHeatmapData } from "../_graphs/heatmapUtils"; -import type { DashboardPageProps } from "../getExercisesWhereClause"; -import { getExercisesWhereClause } from "../getExercisesWhereClause"; -import { RandomFacts } from "../_graphs/randomFacts"; - -//TODO: infinte scroll -const ExercisesByMonthGrid = async (props: DashboardPageProps) => { - const session = await getServerSession(authOptions); - - if (!session?.user.id) { - return redirect("/"); - } - - const exercises = await getExercises(session.user.id, props.searchParams); - - return ( - <> - {getExercisesByMonth(exercises).map((group) => { - return ( - - - - - - {group.exercises.map((exercise) => { - return ( - - - - {exercise.name} - - - - - ); - })} - - - - exercises count - - - ({ - exerciseName: exercise.name, - frequency: exercise.data.length, - }))} - /> - - - - - heatmap - - - - - - - - random facts - - - - - - - ); - })} - - ); -}; - -export default ExercisesByMonthGrid; - -type ExercisesByMonth = { - date: string; - exercises: ExerciseWithData[]; -}[]; - -const getExercisesByMonth = (exercises: ExerciseWithData[]) => { - const exercisesByMonth: ExercisesByMonth = []; - - for (const exercise of exercises) { - for (const data of exercise.data) { - const firstDayOfMonthDate = dateAsYearMonthDayFormat( - new Date(new Date(data.doneAt).setDate(1)), - ); - - const entry = exercisesByMonth.find( - (entry) => entry.date === firstDayOfMonthDate, - ); - - if (!entry) { - exercisesByMonth.push({ - date: firstDayOfMonthDate, - exercises: [{ ...exercise, data: [data] }], - }); - continue; - } - - const exerciseInEntry = entry.exercises.find( - (ex) => ex.id === exercise.id, - ); - - if (!exerciseInEntry) { - entry.exercises.push({ ...exercise, data: [data] }); - continue; - } - - exerciseInEntry.data.push(data); - } - } - - return exercisesByMonth.sort( - (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime(), - ); -}; - -const getExercises = ( - userId: User["id"], - searchParams: DashboardPageProps["searchParams"], -) => { - return db.query.exercises.findMany({ - with: { - data: { orderBy: (data, { desc }) => [desc(data.doneAt)] }, - }, - where: () => getExercisesWhereClause({ searchParams, userId }), - }); -}; diff --git a/src/app/dashboard/@newExerciseForm/newExerciseNameForm.tsx b/src/app/dashboard/@newExerciseForm/newExerciseNameForm.tsx deleted file mode 100644 index 79150d0b..00000000 --- a/src/app/dashboard/@newExerciseForm/newExerciseNameForm.tsx +++ /dev/null @@ -1,88 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { ToastAction } from "@/components/ui/toast"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { useToast } from "@/components/ui/use-toast"; -import { Plus } from "lucide-react"; -import { experimental_useFormStatus as useFormStatus } from "react-dom"; -import { Loader } from "@/components/ui/loader"; -import { useState } from "react"; -import { api } from "@/trpc/react"; - -export const NewExerciseForm = () => { - const [name, setName] = useState(""); - const { toast } = useToast(); - const utils = api.useUtils(); - - const createExercise = api.exercise.create.useMutation({ - onSuccess: () => { - setName(""); - }, - onError: (error) => { - toast({ - variant: "destructive", - title: "Something went wrong", - description: error.message, - action: ( - void createExercise.mutate({ name })} - > - Try again - - ), - }); - }, - onSettled: async () => { - await utils.exercise.all.invalidate(); - }, - }); - - return ( -
createExercise.mutate({ name })} - className="mx-auto flex w-full max-w-2xl gap-2" - > - setName(e.target.value)} - autoComplete="off" - /> - - - - -
- -
-
- -

add

-
-
-
-
- ); -}; - -const SubmitButton = () => { - const formStatus = useFormStatus(); - return ( - - ); -}; diff --git a/src/app/dashboard/@newExerciseForm/page.tsx b/src/app/dashboard/@newExerciseForm/page.tsx deleted file mode 100644 index ff2eed04..00000000 --- a/src/app/dashboard/@newExerciseForm/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { NewExerciseForm } from "./newExerciseNameForm"; - -const GridExercises = () => { - return ; -}; - -export default GridExercises; diff --git a/src/app/dashboard-new/_components/allExercisesTimeline/allExercisesGrid.tsx b/src/app/dashboard/_components/allExercisesTimeline/allExercisesGrid.tsx similarity index 90% rename from src/app/dashboard-new/_components/allExercisesTimeline/allExercisesGrid.tsx rename to src/app/dashboard/_components/allExercisesTimeline/allExercisesGrid.tsx index 4230e82f..4699f700 100644 --- a/src/app/dashboard-new/_components/allExercisesTimeline/allExercisesGrid.tsx +++ b/src/app/dashboard/_components/allExercisesTimeline/allExercisesGrid.tsx @@ -2,13 +2,7 @@ import { type RouterInputs, type RouterOutputs, api } from "@/trpc/react"; import { type ComponentPropsWithoutRef } from "react"; -import { GridLayout } from "@/app/dashboard/_grid/gridLayout"; -import { GridItem } from "@/app/dashboard/_grid/gridItem"; -import { ExerciseMuscleGroupsDropdown } from "@/app/dashboard/@allExercisesGrid/exerciseMuscleGroups"; import { MoreHorizontal, Tag } from "lucide-react"; -import { LineGraph } from "@/app/dashboard/_graphs/lineGraph"; -import { RadarGraph } from "@/app/dashboard/_graphs/radarGraph"; -import { RandomFacts } from "@/app/dashboard/_graphs/randomFacts"; import { DropdownMenu, DropdownMenuContent, @@ -26,12 +20,18 @@ import { import { useMutationState } from "@tanstack/react-query"; import { Skeleton } from "@/components/ui/skeleton"; import { getQueryKey } from "@trpc/react-query"; -import { UpdateExerciseNameDialog } from "@/app/dashboard/_modals/updateExerciseNameDialog"; -import { DeleteExerciseAlertDialog } from "@/app/dashboard/_modals/deleteExerciseAlertDialog"; import { DragComponent, SortableGrid } from "./sortableGrid"; import { pluralize } from "@/lib/utils"; import { useExercises } from "../useExercises"; import { useDashboardSearchParams } from "../useDashboardSearchParams"; +import { GridLayout } from "../grid/gridLayout"; +import { GridItem } from "../grid/gridItem"; +import { DeleteExerciseAlertDialog } from "../modals/deleteExerciseAlertDialog"; +import { UpdateExerciseNameDialog } from "../modals/updateExerciseNameDialog"; +import { LineGraph } from "../graphs/lineGraph"; +import { RadarGraph } from "../graphs/radarGraph"; +import { RandomFacts } from "../graphs/randomFacts"; +import { ExerciseMuscleGroupsDropdown } from "./exerciseMuscleGroups"; export const AllExercisesGrid = () => { const dashboardShareParams = useDashboardSearchParams(); diff --git a/src/app/dashboard-new/_components/allExercisesTimeline/allExercisesTimeline.tsx b/src/app/dashboard/_components/allExercisesTimeline/allExercisesTimeline.tsx similarity index 100% rename from src/app/dashboard-new/_components/allExercisesTimeline/allExercisesTimeline.tsx rename to src/app/dashboard/_components/allExercisesTimeline/allExercisesTimeline.tsx diff --git a/src/app/dashboard/@allExercisesGrid/exerciseMuscleGroups.tsx b/src/app/dashboard/_components/allExercisesTimeline/exerciseMuscleGroups.tsx similarity index 100% rename from src/app/dashboard/@allExercisesGrid/exerciseMuscleGroups.tsx rename to src/app/dashboard/_components/allExercisesTimeline/exerciseMuscleGroups.tsx diff --git a/src/app/dashboard-new/_components/allExercisesTimeline/filters.tsx b/src/app/dashboard/_components/allExercisesTimeline/filters.tsx similarity index 100% rename from src/app/dashboard-new/_components/allExercisesTimeline/filters.tsx rename to src/app/dashboard/_components/allExercisesTimeline/filters.tsx diff --git a/src/app/dashboard-new/_components/allExercisesTimeline/sortableGrid.tsx b/src/app/dashboard/_components/allExercisesTimeline/sortableGrid.tsx similarity index 100% rename from src/app/dashboard-new/_components/allExercisesTimeline/sortableGrid.tsx rename to src/app/dashboard/_components/allExercisesTimeline/sortableGrid.tsx diff --git a/src/app/dashboard/_graphs/heatmapGraph.tsx b/src/app/dashboard/_components/graphs/heatmapGraph.tsx similarity index 100% rename from src/app/dashboard/_graphs/heatmapGraph.tsx rename to src/app/dashboard/_components/graphs/heatmapGraph.tsx diff --git a/src/app/dashboard/_graphs/heatmapUtils.ts b/src/app/dashboard/_components/graphs/heatmapUtils.ts similarity index 100% rename from src/app/dashboard/_graphs/heatmapUtils.ts rename to src/app/dashboard/_components/graphs/heatmapUtils.ts diff --git a/src/app/dashboard/_graphs/lineGraph.tsx b/src/app/dashboard/_components/graphs/lineGraph.tsx similarity index 100% rename from src/app/dashboard/_graphs/lineGraph.tsx rename to src/app/dashboard/_components/graphs/lineGraph.tsx diff --git a/src/app/dashboard/_graphs/radarGraph.tsx b/src/app/dashboard/_components/graphs/radarGraph.tsx similarity index 100% rename from src/app/dashboard/_graphs/radarGraph.tsx rename to src/app/dashboard/_components/graphs/radarGraph.tsx diff --git a/src/app/dashboard/_graphs/randomFacts.tsx b/src/app/dashboard/_components/graphs/randomFacts.tsx similarity index 100% rename from src/app/dashboard/_graphs/randomFacts.tsx rename to src/app/dashboard/_components/graphs/randomFacts.tsx diff --git a/src/app/dashboard/_grid/gridItem.tsx b/src/app/dashboard/_components/grid/gridItem.tsx similarity index 100% rename from src/app/dashboard/_grid/gridItem.tsx rename to src/app/dashboard/_components/grid/gridItem.tsx diff --git a/src/app/dashboard/_grid/gridLayout.tsx b/src/app/dashboard/_components/grid/gridLayout.tsx similarity index 100% rename from src/app/dashboard/_grid/gridLayout.tsx rename to src/app/dashboard/_components/grid/gridLayout.tsx diff --git a/src/app/dashboard/_modals/deleteExerciseAlertDialog.tsx b/src/app/dashboard/_components/modals/deleteExerciseAlertDialog.tsx similarity index 100% rename from src/app/dashboard/_modals/deleteExerciseAlertDialog.tsx rename to src/app/dashboard/_components/modals/deleteExerciseAlertDialog.tsx diff --git a/src/app/dashboard/_modals/updateExerciseNameDialog.tsx b/src/app/dashboard/_components/modals/updateExerciseNameDialog.tsx similarity index 100% rename from src/app/dashboard/_modals/updateExerciseNameDialog.tsx rename to src/app/dashboard/_components/modals/updateExerciseNameDialog.tsx diff --git a/src/app/dashboard-new/_components/monthlyExercisesTimeline/monthlyExercisesTimeline.tsx b/src/app/dashboard/_components/monthlyExercisesTimeline/monthlyExercisesTimeline.tsx similarity index 85% rename from src/app/dashboard-new/_components/monthlyExercisesTimeline/monthlyExercisesTimeline.tsx rename to src/app/dashboard/_components/monthlyExercisesTimeline/monthlyExercisesTimeline.tsx index 7fd78efb..ef05b1fb 100644 --- a/src/app/dashboard-new/_components/monthlyExercisesTimeline/monthlyExercisesTimeline.tsx +++ b/src/app/dashboard/_components/monthlyExercisesTimeline/monthlyExercisesTimeline.tsx @@ -1,17 +1,17 @@ "use client"; -import { HeatmapGraph } from "@/app/dashboard/_graphs/heatmapGraph"; -import { prepareHeatmapData } from "@/app/dashboard/_graphs/heatmapUtils"; -import { LineGraph } from "@/app/dashboard/_graphs/lineGraph"; -import { RadarGraph } from "@/app/dashboard/_graphs/radarGraph"; -import { RandomFacts } from "@/app/dashboard/_graphs/randomFacts"; -import { GridItem } from "@/app/dashboard/_grid/gridItem"; -import { GridLayout } from "@/app/dashboard/_grid/gridLayout"; -import { TimelineContainer } from "@/app/dashboard/timelineContainer"; import { Badge } from "@/components/ui/badge"; import { dateAsYearMonthDayFormat } from "@/lib/date"; import type { RouterOutputs } from "@/trpc/react"; import { useExercises } from "../useExercises"; +import { GridLayout } from "../grid/gridLayout"; +import { GridItem } from "../grid/gridItem"; +import { LineGraph } from "../graphs/lineGraph"; +import { RadarGraph } from "../graphs/radarGraph"; +import { HeatmapGraph } from "../graphs/heatmapGraph"; +import { prepareHeatmapData } from "../graphs/heatmapUtils"; +import { RandomFacts } from "../graphs/randomFacts"; +import { Timeline } from "../timeline"; export const MonthlyExercisesTimeline = () => { const exercises = useExercises(); @@ -19,7 +19,7 @@ export const MonthlyExercisesTimeline = () => { return ( <> {getExercisesByMonth(exercises).map((group) => ( - + + ))} ); diff --git a/src/app/dashboard-new/_components/newExerciseForm/newExerciseForm.tsx b/src/app/dashboard/_components/newExerciseForm/newExerciseForm.tsx similarity index 100% rename from src/app/dashboard-new/_components/newExerciseForm/newExerciseForm.tsx rename to src/app/dashboard/_components/newExerciseForm/newExerciseForm.tsx diff --git a/src/app/dashboard-new/_components/timeline.tsx b/src/app/dashboard/_components/timeline.tsx similarity index 100% rename from src/app/dashboard-new/_components/timeline.tsx rename to src/app/dashboard/_components/timeline.tsx diff --git a/src/app/dashboard-new/_components/useDashboardSearchParams.ts b/src/app/dashboard/_components/useDashboardSearchParams.ts similarity index 100% rename from src/app/dashboard-new/_components/useDashboardSearchParams.ts rename to src/app/dashboard/_components/useDashboardSearchParams.ts diff --git a/src/app/dashboard-new/_components/useExercises.ts b/src/app/dashboard/_components/useExercises.ts similarity index 100% rename from src/app/dashboard-new/_components/useExercises.ts rename to src/app/dashboard/_components/useExercises.ts diff --git a/src/app/dashboard/getExercisesWhereClause.ts b/src/app/dashboard/getExercisesWhereClause.ts deleted file mode 100644 index 80df8e3b..00000000 --- a/src/app/dashboard/getExercisesWhereClause.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { exercises, muscleGroupsEnum } from "@/db/schema"; -import type { Exercise, User } from "@/db/types"; -import { and, arrayOverlaps, eq, ilike } from "drizzle-orm"; - -export type DashboardPageProps = { - searchParams: { tags?: string; search?: string }; -}; - -type Props = DashboardPageProps & { userId: User["id"] }; - -export const getExercisesWhereClause = ({ searchParams, userId }: Props) => { - const muscleGroups = searchParams.tags - ? (searchParams.tags - .split(",") - .filter((item) => - (muscleGroupsEnum.enumValues as string[]).includes(item) - ) as Exercise["muscleGroups"]) - : null; - - if (muscleGroups && searchParams.search) { - return and( - eq(exercises.userId, userId), - arrayOverlaps(exercises.muscleGroups, muscleGroups), - ilike(exercises.name, `%${searchParams.search}%`) - ); - } - - if (!searchParams.tags && searchParams.search) { - return and( - eq(exercises.userId, userId), - ilike(exercises.name, `%${searchParams.search}%`) - ); - } - - if (muscleGroups && !searchParams.search) { - return and( - eq(exercises.userId, userId), - arrayOverlaps(exercises.muscleGroups, muscleGroups) - ); - } - - return and(eq(exercises.userId, userId)); -}; diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx index feb8fd83..d9cbe2c6 100644 --- a/src/app/dashboard/layout.tsx +++ b/src/app/dashboard/layout.tsx @@ -1,33 +1,21 @@ import { DashboardBackground } from "@/components/ui/dashboardBackground"; -import type { ReactNode, ComponentProps, PropsWithChildren } from "react"; +import type { ComponentPropsWithoutRef, PropsWithChildren } from "react"; -type Props = { - newExerciseForm: ReactNode; - allExercisesGrid: ReactNode; - exercisesByMonthGrid: ReactNode; -} & PropsWithChildren; - -const Layout = (props: Props) => { +const Layout = (props: PropsWithChildren) => { return ( - - {props.newExerciseForm} - {props.allExercisesGrid} - {props.exercisesByMonthGrid} - + {props.children} - - {props.children} ); }; export default Layout; -const Container = (props: ComponentProps<"main">) => { +const Container = (props: ComponentPropsWithoutRef<"main">) => { return (
) => { ); }; -const ContentContainer = (props: ComponentProps<"div">) => { +const ContentContainer = (props: ComponentPropsWithoutRef<"div">) => { return (
) => { ); }; -const BackgroundContainer = (props: ComponentProps<"div">) => { +const BackgroundContainer = (props: ComponentPropsWithoutRef<"div">) => { return (
{ - return null; +import { NewExerciseForm } from "./_components/newExerciseForm/newExerciseForm"; +import { getServerAuthSession } from "@/server/auth"; +import { redirect } from "next/navigation"; +import { createSSRHelper } from "@/trpc/server"; +import { HydrationBoundary, dehydrate } from "@tanstack/react-query"; +import { AllExercisesTimeline } from "./_components/allExercisesTimeline/allExercisesTimeline"; +import { MonthlyExercisesTimeline } from "./_components/monthlyExercisesTimeline/monthlyExercisesTimeline"; + +const Page = async () => { + const session = await getServerAuthSession(); + + if (!session?.user.id) { + return redirect("/"); + } + + const helpers = await createSSRHelper(); + await helpers.exercise.all.prefetch(); + + return ( + <> + + + + + + + + + + + ); }; export default Page; diff --git a/src/app/dashboard/timelineContainer.tsx b/src/app/dashboard/timelineContainer.tsx deleted file mode 100644 index 216c11d3..00000000 --- a/src/app/dashboard/timelineContainer.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { cn } from "@/lib/utils"; -import type { ComponentProps } from "react"; - -export const TimelineContainer = (props: ComponentProps<"div">) => { - return ( -
- ); -}; diff --git a/src/app/header.tsx b/src/app/header.tsx index 29d09c35..faedcfe4 100644 --- a/src/app/header.tsx +++ b/src/app/header.tsx @@ -453,10 +453,7 @@ export const Header = () => { const pathname = usePathname().split("/"); const showExecisesPath = pathname[1] === "exercises"; - const showDashboardPath = - pathname[1] === "dashboard" || - pathname[1] === "dashboard-new" || - showExecisesPath; + const showDashboardPath = pathname[1] === "dashboard" || showExecisesPath; const exerciseId = pathname[2]; return ( diff --git a/src/app/page.tsx b/src/app/page.tsx index a4932b13..4f214f00 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -6,15 +6,6 @@ import { ArrowRight, GripVertical, MoreHorizontal, Tag } from "lucide-react"; import Link from "next/link"; import type { ComponentProps, ComponentPropsWithoutRef } from "react"; import { twMerge } from "tailwind-merge"; -import { TimelineContainer } from "./dashboard/timelineContainer"; -import { GridItem } from "./dashboard/_grid/gridItem"; -import { LineGraph } from "./dashboard/_graphs/lineGraph"; -import { GridLayout } from "./dashboard/_grid/gridLayout"; -import { Badge } from "@/components/ui/badge"; -import { RadarGraph } from "./dashboard/_graphs/radarGraph"; -import { RandomFacts } from "./dashboard/_graphs/randomFacts"; -import { HeatmapGraph } from "./dashboard/_graphs/heatmapGraph"; -import { prepareHeatmapData } from "./dashboard/_graphs/heatmapUtils"; import { mockExercises } from "@/lib/mock-data"; import { Tooltip, @@ -26,6 +17,15 @@ import { ExerciseDetailsProvider } from "./exercises/[id]/@exerciseDetails/exerc import { ExerciseGraphCard } from "./exercises/[id]/@exerciseDetails/_graph/exerciseGraphCard"; import { ExerciseTableCard } from "./exercises/[id]/@exerciseDetails/_table/exerciseTableCard"; import { exerciseTableColumnsWithoutActions } from "./exercises/[id]/@exerciseDetails/_table/_table/columns"; +import { Badge } from "@/components/ui/badge"; +import { GridLayout } from "./dashboard/_components/grid/gridLayout"; +import { GridItem } from "./dashboard/_components/grid/gridItem"; +import { LineGraph } from "./dashboard/_components/graphs/lineGraph"; +import { RadarGraph } from "./dashboard/_components/graphs/radarGraph"; +import { HeatmapGraph } from "./dashboard/_components/graphs/heatmapGraph"; +import { prepareHeatmapData } from "./dashboard/_components/graphs/heatmapUtils"; +import { RandomFacts } from "./dashboard/_components/graphs/randomFacts"; +import { Timeline } from "./dashboard/_components/timeline"; const HomePage = async () => { await redirectIfSignedIn(); @@ -110,7 +110,7 @@ const FeatureOne = () => { breakdown of your achievements each month. - + + ); diff --git a/src/db/schema.ts b/src/db/schema.ts index a05e9636..89613539 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -12,6 +12,7 @@ import { pgEnum, } from "drizzle-orm/pg-core"; import type { AdapterAccount } from "@auth/core/adapters"; +import { sql } from "drizzle-orm"; export const users = pgTable("user", { id: text("id").notNull().primaryKey(), @@ -40,7 +41,7 @@ export const accounts = pgTable( }, (account) => ({ compoundKey: primaryKey(account.provider, account.providerAccountId), - }) + }), ); export const sessions = pgTable("session", { @@ -60,7 +61,7 @@ export const verificationTokens = pgTable( }, (vt) => ({ compoundKey: primaryKey(vt.identifier, vt.token), - }) + }), ); export const muscleGroupsEnum = pgEnum("muscle_groups", [ @@ -89,11 +90,11 @@ export const exercises = pgTable( muscleGroups: muscleGroupsEnum("muscle_groups") .array() .notNull() - .default([]), + .default(sql`'{}'`), }, (exercise) => ({ unq: unique().on(exercise.userId, exercise.name), - }) + }), ); export const exerciseGridPosition = pgTable("exercise_grid_position", { @@ -122,5 +123,5 @@ export const exercisesData = pgTable( }, (exerciseData) => ({ unq: unique().on(exerciseData.doneAt, exerciseData.exerciseId), - }) + }), );