diff --git a/backend/app/Http/Controllers/AuthController.php b/backend/app/Http/Controllers/AuthController.php new file mode 100644 index 0000000..2459fb2 --- /dev/null +++ b/backend/app/Http/Controllers/AuthController.php @@ -0,0 +1,60 @@ +validate([ + 'name' => 'required', + 'email' => 'required|email|unique:users', + 'password' => 'required|min:6' + ]); + + $user = User::create([ + 'name' => $request->name, + 'email' => $request->email, + 'password' => Hash::make($request->password), + 'level' => 1, + 'xp' => 0 + ]); + + $token = $user->createToken('api_token')->plainTextToken; + + return response()->json([ + 'user' => $user, + 'token' => $token + ], 201); + } + + public function login(Request $request) + { + $request->validate([ + 'email' => 'required|email', + 'password' => 'required' + ]); + + $user = User::where('email', $request->email)->first(); + + if (!$user || !Hash::check($request->password, $user->password)) { + return response()->json(['message' => 'Invalid credentials'], 401); + } + + $token = $user->createToken('api_token')->plainTextToken; + + return response()->json([ + 'token' => $token, + 'user' => $user + ]); + } + + public function me(Request $request) + { + return response()->json(['user' => $request->user()]); + } +} diff --git a/backend/app/Http/Controllers/QuestController.php b/backend/app/Http/Controllers/QuestController.php new file mode 100644 index 0000000..5aff741 --- /dev/null +++ b/backend/app/Http/Controllers/QuestController.php @@ -0,0 +1,70 @@ +user()->id)->where('is_completed', false)->get(); + return response()->json($quests); + } + + public function generate(Request $request) + { + // Vereinfachte Logik: Nimmt die letzten 5 offenen Tasks und macht daraus Quests + $tasks = Task::where('user_id', $request->user()->id)->limit(5)->get(); + + $quests = []; + foreach ($tasks as $task) { + $quests[] = Quest::create([ + 'user_id' => $request->user()->id, + 'task_id' => $task->id, + 'title' => $task->title, + 'category' => $task->category, + 'due_date' => $task->due_date, + 'xp_reward' => 50, + 'is_completed' => false + ]); + } + + return response()->json($quests, 201); + } + + public function complete(Request $request, $id) + { + $quest = Quest::where('user_id', $request->user()->id)->findOrFail($id); + + if ($quest->is_completed) { + return response()->json(['message' => 'Quest already completed'], 400); + } + + // Mark as completed + $quest->update(['is_completed' => true]); + + $user = $request->user(); + $user->xp += $quest->xp_reward; + + // Level-Up Check (vereinfachte Logik) + $xpForNextLevel = $user->level * 100; + $levelUp = false; + while ($user->xp >= $xpForNextLevel) { + $user->level += 1; + $user->xp = $user->xp - $xpForNextLevel; + $xpForNextLevel = $user->level * 100; + $levelUp = true; + } + $user->save(); + + return response()->json([ + 'quest' => $quest, + 'xp_gained' => $quest->xp_reward, + 'new_level' => $user->level, + 'level_up' => $levelUp + ]); + } +} diff --git a/backend/app/Http/Controllers/RewardController.php b/backend/app/Http/Controllers/RewardController.php new file mode 100644 index 0000000..86b7eed --- /dev/null +++ b/backend/app/Http/Controllers/RewardController.php @@ -0,0 +1,22 @@ +json($rewards); + } + + public function unlocked(Request $request) + { + $user = $request->user(); + $unlocked = $user->belongsToMany(Reward::class, 'reward_user')->get(); + return response()->json($unlocked); + } +} diff --git a/backend/app/Http/Controllers/TaskController.php b/backend/app/Http/Controllers/TaskController.php new file mode 100644 index 0000000..fb61a7e --- /dev/null +++ b/backend/app/Http/Controllers/TaskController.php @@ -0,0 +1,57 @@ +user()->id)->get(); + return response()->json($tasks); + } + + public function store(Request $request) + { + $request->validate([ + 'title' => 'required', + 'category' => 'in:daily,weekend,vacation,work', + 'priority' => 'in:low,medium,high' + ]); + + $task = Task::create([ + 'user_id' => $request->user()->id, + 'title' => $request->title, + 'description' => $request->description, + 'category' => $request->category ?? 'daily', + 'priority' => $request->priority ?? 'medium', + 'due_date' => $request->due_date + ]); + + return response()->json($task, 201); + } + + public function show(Request $request, $id) + { + $task = Task::where('user_id', $request->user()->id)->findOrFail($id); + return response()->json($task); + } + + public function update(Request $request, $id) + { + $task = Task::where('user_id', $request->user()->id)->findOrFail($id); + + $task->update($request->only('title', 'description', 'category', 'priority', 'due_date')); + + return response()->json($task); + } + + public function destroy(Request $request, $id) + { + $task = Task::where('user_id', $request->user()->id)->findOrFail($id); + $task->delete(); + return response()->noContent(); + } +} diff --git a/backend/app/Http/Controllers/UserController.php b/backend/app/Http/Controllers/UserController.php new file mode 100644 index 0000000..634d9d9 --- /dev/null +++ b/backend/app/Http/Controllers/UserController.php @@ -0,0 +1,25 @@ +user(); + $xpForNextLevel = $user->level * 100; + + // Finde noch nicht freigeschaltete Rewards, die in Reichweite sind + $upcomingRewards = Reward::where('unlocked_at_level', '>', $user->level)->limit(5)->get(); + + return response()->json([ + 'level' => $user->level, + 'xp' => $user->xp, + 'xp_for_next_level' => $xpForNextLevel, + 'upcoming_rewards' => $upcomingRewards + ]); + } +} diff --git a/backend/app/Models/Quest.php b/backend/app/Models/Quest.php new file mode 100644 index 0000000..1f6815e --- /dev/null +++ b/backend/app/Models/Quest.php @@ -0,0 +1,31 @@ +belongsTo(User::class); + } + + public function task() + { + return $this->belongsTo(Task::class); + } +} diff --git a/backend/app/Models/Reward.php b/backend/app/Models/Reward.php new file mode 100644 index 0000000..a219ed3 --- /dev/null +++ b/backend/app/Models/Reward.php @@ -0,0 +1,22 @@ +belongsToMany(User::class, 'reward_user'); + } +} diff --git a/backend/app/Models/Task.php b/backend/app/Models/Task.php new file mode 100644 index 0000000..386a0a6 --- /dev/null +++ b/backend/app/Models/Task.php @@ -0,0 +1,25 @@ +belongsTo(User::class); + } +} diff --git a/backend/app/Models/User.php b/backend/app/Models/User.php index def621f..9b450b9 100644 --- a/backend/app/Models/User.php +++ b/backend/app/Models/User.php @@ -20,6 +20,8 @@ class User extends Authenticatable 'name', 'email', 'password', + 'level', + 'xp' ]; /** diff --git a/backend/config/app.php b/backend/config/app.php index f467267..63f9d3c 100644 --- a/backend/config/app.php +++ b/backend/config/app.php @@ -13,7 +13,7 @@ return [ | */ - 'name' => env('APP_NAME', 'Laravel'), + 'name' => env('APP_NAME', 'ADHD Home Quest'), /* |-------------------------------------------------------------------------- @@ -26,7 +26,7 @@ return [ | */ - 'env' => env('APP_ENV', 'production'), + 'env' => env('APP_ENV', 'development'), /* |-------------------------------------------------------------------------- @@ -39,7 +39,7 @@ return [ | */ - 'debug' => (bool) env('APP_DEBUG', false), + 'debug' => (bool) env('APP_DEBUG', true), /* |-------------------------------------------------------------------------- @@ -65,7 +65,7 @@ return [ | */ - 'timezone' => env('APP_TIMEZONE', 'UTC'), + 'timezone' => env('APP_TIMEZONE', 'CET'), /* |-------------------------------------------------------------------------- diff --git a/backend/database/migrations/2024_12_16_084121_create_users_table.php b/backend/database/migrations/2024_12_16_084121_create_users_table.php new file mode 100644 index 0000000..92d02f3 --- /dev/null +++ b/backend/database/migrations/2024_12_16_084121_create_users_table.php @@ -0,0 +1,30 @@ +id(); + $table->string('name'); + $table->string('email')->unique(); + $table->string('password'); + $table->integer('level')->default(1); + $table->integer('xp')->default(0); + $table->timestamps(); + }); + } + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('users'); + } +}; diff --git a/backend/database/migrations/2024_12_16_084321_create_tasks_table.php b/backend/database/migrations/2024_12_16_084321_create_tasks_table.php new file mode 100644 index 0000000..40a44c9 --- /dev/null +++ b/backend/database/migrations/2024_12_16_084321_create_tasks_table.php @@ -0,0 +1,33 @@ +id(); + $table->unsignedBigInteger('user_id'); + $table->string('title'); + $table->text('description')->nullable(); + $table->enum('category', ['daily', 'weekend', 'vacation', 'work'])->default('daily'); + $table->enum('priority', ['low', 'medium', 'high'])->default('medium'); + $table->dateTime('due_date')->nullable(); + $table->timestamps(); + + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + }); + } + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('tasks'); + } +}; diff --git a/backend/database/migrations/2024_12_16_084521_create_quest_table.php b/backend/database/migrations/2024_12_16_084521_create_quest_table.php new file mode 100644 index 0000000..6728852 --- /dev/null +++ b/backend/database/migrations/2024_12_16_084521_create_quest_table.php @@ -0,0 +1,36 @@ +id(); + $table->unsignedBigInteger('user_id'); + $table->unsignedBigInteger('task_id'); + $table->string('title'); + $table->string('category'); + $table->dateTime('due_date')->nullable(); + $table->integer('xp_reward')->default(50); + $table->boolean('is_completed')->default(false); + $table->timestamps(); + + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->foreign('task_id')->references('id')->on('tasks')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('quests'); + } +}; diff --git a/backend/database/migrations/2024_12_16_084621_create_rewards_table.php b/backend/database/migrations/2024_12_16_084621_create_rewards_table.php new file mode 100644 index 0000000..6be9c0e --- /dev/null +++ b/backend/database/migrations/2024_12_16_084621_create_rewards_table.php @@ -0,0 +1,41 @@ +id(); + $table->string('name'); + $table->text('description')->nullable(); + $table->integer('unlocked_at_level')->default(2); + $table->timestamps(); + }); + + // Optionale Pivot-Tabelle für freigeschaltete Rewards + Schema::create('reward_user', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('user_id'); + $table->unsignedBigInteger('reward_id'); + $table->timestamps(); + + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->foreign('reward_id')->references('id')->on('rewards')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('rewards'); + Schema::dropIfExists('reward_user'); + } +}; diff --git a/backend/resources/views/welcome.blade.php b/backend/resources/views/welcome.blade.php index a9898e3..73559a9 100644 --- a/backend/resources/views/welcome.blade.php +++ b/backend/resources/views/welcome.blade.php @@ -55,111 +55,7 @@
-
- -
- Laravel documentation screenshot - -
-
-
-
-
- -
- -
-

Documentation

- -

- Laravel has wonderful documentation covering every aspect of the framework. Whether you are a newcomer or have prior experience with Laravel, we recommend reading our documentation from beginning to end. -

-
-
- - -
-
- - -
- -
- -
-

Laracasts

- -

- Laracasts offers thousands of video tutorials on Laravel, PHP, and JavaScript development. Check them out, see for yourself, and massively level up your development skills in the process. -

-
- - -
- - -
- -
- -
-

Laravel News

- -

- Laravel News is a community driven portal and newsletter aggregating all of the latest and most important news in the Laravel ecosystem, including new package releases and tutorials. -

-
- - -
- -
-
- - - - - -
- -
-

Vibrant Ecosystem

- -

- Laravel's robust library of first-party tools and libraries, such as Forge, Vapor, Nova, Envoyer, and Herd help you take your projects to the next level. Pair them with powerful open source libraries like Cashier, Dusk, Echo, Horizon, Sanctum, Telescope, and more. -

-
-
-