completed story 1.1 with QA tests and fixes
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\AdminLog>
|
||||
*/
|
||||
class AdminLogFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'admin_id' => User::factory()->admin(),
|
||||
'action' => fake()->randomElement(['create', 'update', 'delete', 'login', 'logout']),
|
||||
'target_type' => fake()->randomElement(['User', 'Consultation', 'Timeline', 'Post']),
|
||||
'target_id' => fake()->optional()->numberBetween(1, 100),
|
||||
'old_values' => fake()->optional()->randomElements(['status' => 'pending', 'name' => 'Old Name'], null),
|
||||
'new_values' => fake()->optional()->randomElements(['status' => 'approved', 'name' => 'New Name'], null),
|
||||
'ip_address' => fake()->ipv4(),
|
||||
'created_at' => fake()->dateTimeBetween('-30 days', 'now'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\BlockedTime>
|
||||
*/
|
||||
class BlockedTimeFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'block_date' => fake()->dateTimeBetween('now', '+30 days'),
|
||||
'start_time' => null,
|
||||
'end_time' => null,
|
||||
'reason' => fake()->optional()->sentence(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a full day block.
|
||||
*/
|
||||
public function fullDay(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'start_time' => null,
|
||||
'end_time' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a partial day block with specific times.
|
||||
*/
|
||||
public function partialDay(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'start_time' => '09:00:00',
|
||||
'end_time' => '12:00:00',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\ConsultationStatus;
|
||||
use App\Enums\ConsultationType;
|
||||
use App\Enums\PaymentStatus;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Consultation>
|
||||
*/
|
||||
class ConsultationFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
$consultationType = fake()->randomElement(ConsultationType::cases());
|
||||
$paymentStatus = $consultationType === ConsultationType::Paid
|
||||
? fake()->randomElement([PaymentStatus::Pending, PaymentStatus::Received])
|
||||
: PaymentStatus::NotApplicable;
|
||||
|
||||
return [
|
||||
'user_id' => User::factory(),
|
||||
'booking_date' => fake()->dateTimeBetween('now', '+30 days'),
|
||||
'booking_time' => fake()->time('H:i:s'),
|
||||
'problem_summary' => fake()->paragraph(),
|
||||
'consultation_type' => $consultationType,
|
||||
'payment_amount' => $consultationType === ConsultationType::Paid ? fake()->randomFloat(2, 50, 500) : null,
|
||||
'payment_status' => $paymentStatus,
|
||||
'status' => fake()->randomElement(ConsultationStatus::cases()),
|
||||
'admin_notes' => fake()->optional()->paragraph(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a free consultation.
|
||||
*/
|
||||
public function free(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'consultation_type' => ConsultationType::Free,
|
||||
'payment_amount' => null,
|
||||
'payment_status' => PaymentStatus::NotApplicable,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a paid consultation.
|
||||
*/
|
||||
public function paid(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'consultation_type' => ConsultationType::Paid,
|
||||
'payment_amount' => fake()->randomFloat(2, 50, 500),
|
||||
'payment_status' => fake()->randomElement([PaymentStatus::Pending, PaymentStatus::Received]),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a pending consultation.
|
||||
*/
|
||||
public function pending(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'status' => ConsultationStatus::Pending,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an approved consultation.
|
||||
*/
|
||||
public function approved(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'status' => ConsultationStatus::Approved,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a completed consultation.
|
||||
*/
|
||||
public function completed(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'status' => ConsultationStatus::Completed,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Notification>
|
||||
*/
|
||||
class NotificationFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'user_id' => User::factory(),
|
||||
'type' => fake()->randomElement(['consultation_approved', 'consultation_rejected', 'timeline_update', 'new_post']),
|
||||
'data' => [
|
||||
'message' => fake()->sentence(),
|
||||
'action_url' => fake()->url(),
|
||||
],
|
||||
'read_at' => null,
|
||||
'sent_at' => fake()->optional()->dateTimeBetween('-7 days', 'now'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a read notification.
|
||||
*/
|
||||
public function read(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'read_at' => fake()->dateTimeBetween('-7 days', 'now'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an unread notification.
|
||||
*/
|
||||
public function unread(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'read_at' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sent notification.
|
||||
*/
|
||||
public function sent(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'sent_at' => fake()->dateTimeBetween('-7 days', 'now'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\PostStatus;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Post>
|
||||
*/
|
||||
class PostFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'title' => [
|
||||
'ar' => fake('ar_SA')->sentence(),
|
||||
'en' => fake()->sentence(),
|
||||
],
|
||||
'body' => [
|
||||
'ar' => fake('ar_SA')->paragraphs(3, true),
|
||||
'en' => fake()->paragraphs(3, true),
|
||||
],
|
||||
'status' => PostStatus::Draft,
|
||||
'published_at' => null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a published post.
|
||||
*/
|
||||
public function published(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'status' => PostStatus::Published,
|
||||
'published_at' => fake()->dateTimeBetween('-30 days', 'now'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a draft post.
|
||||
*/
|
||||
public function draft(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'status' => PostStatus::Draft,
|
||||
'published_at' => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\TimelineStatus;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Timeline>
|
||||
*/
|
||||
class TimelineFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'user_id' => User::factory(),
|
||||
'case_name' => fake()->sentence(3),
|
||||
'case_reference' => fake()->boolean(70) ? fake()->unique()->regexify('[A-Z]{2}-[0-9]{4}-[0-9]{3}') : null,
|
||||
'status' => TimelineStatus::Active,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an active timeline.
|
||||
*/
|
||||
public function active(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'status' => TimelineStatus::Active,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an archived timeline.
|
||||
*/
|
||||
public function archived(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'status' => TimelineStatus::Archived,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a timeline with a case reference.
|
||||
*/
|
||||
public function withReference(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'case_reference' => fake()->unique()->regexify('[A-Z]{2}-[0-9]{4}-[0-9]{3}'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Timeline;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\TimelineUpdate>
|
||||
*/
|
||||
class TimelineUpdateFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'timeline_id' => Timeline::factory(),
|
||||
'admin_id' => User::factory()->admin(),
|
||||
'update_text' => fake()->paragraph(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\UserStatus;
|
||||
use App\Enums\UserType;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
@@ -24,14 +26,16 @@ class UserFactory extends Factory
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->name(),
|
||||
'user_type' => UserType::Individual,
|
||||
'full_name' => fake()->name(),
|
||||
'national_id' => fake()->numerify('#########'),
|
||||
'email' => fake()->unique()->safeEmail(),
|
||||
'email_verified_at' => now(),
|
||||
'phone' => fake()->phoneNumber(),
|
||||
'password' => static::$password ??= Hash::make('password'),
|
||||
'status' => UserStatus::Active,
|
||||
'preferred_language' => fake()->randomElement(['ar', 'en']),
|
||||
'email_verified_at' => now(),
|
||||
'remember_token' => Str::random(10),
|
||||
'two_factor_secret' => Str::random(10),
|
||||
'two_factor_recovery_codes' => Str::random(10),
|
||||
'two_factor_confirmed_at' => now(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -45,6 +49,81 @@ class UserFactory extends Factory
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an admin user.
|
||||
*/
|
||||
public function admin(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'user_type' => UserType::Admin,
|
||||
'company_name' => null,
|
||||
'company_cert_number' => null,
|
||||
'contact_person_name' => null,
|
||||
'contact_person_id' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an individual client user.
|
||||
*/
|
||||
public function individual(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'user_type' => UserType::Individual,
|
||||
'company_name' => null,
|
||||
'company_cert_number' => null,
|
||||
'contact_person_name' => null,
|
||||
'contact_person_id' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a company client user.
|
||||
*/
|
||||
public function company(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'user_type' => UserType::Company,
|
||||
'national_id' => null,
|
||||
'company_name' => fake()->company(),
|
||||
'company_cert_number' => fake()->numerify('CR-######'),
|
||||
'contact_person_name' => fake()->name(),
|
||||
'contact_person_id' => fake()->numerify('#########'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a client user (individual or company).
|
||||
*/
|
||||
public function client(): static
|
||||
{
|
||||
return fake()->boolean()
|
||||
? $this->individual()
|
||||
: $this->company();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a deactivated user.
|
||||
*/
|
||||
public function deactivated(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'status' => UserStatus::Deactivated,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model has two-factor authentication configured.
|
||||
*/
|
||||
public function withTwoFactor(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'two_factor_secret' => Str::random(10),
|
||||
'two_factor_recovery_codes' => Str::random(10),
|
||||
'two_factor_confirmed_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model does not have two-factor authentication configured.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\WorkingHour>
|
||||
*/
|
||||
class WorkingHourFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'day_of_week' => fake()->numberBetween(0, 6),
|
||||
'start_time' => '09:00:00',
|
||||
'end_time' => '17:00:00',
|
||||
'is_active' => true,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create working hours for weekdays (Sunday-Thursday, 0-4).
|
||||
*/
|
||||
public function weekdays(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'day_of_week' => fake()->numberBetween(0, 4),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create inactive working hours.
|
||||
*/
|
||||
public function inactive(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'is_active' => false,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -13,10 +13,19 @@ return new class extends Migration
|
||||
{
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('user_type')->default('individual');
|
||||
$table->string('full_name');
|
||||
$table->string('national_id')->nullable();
|
||||
$table->string('company_name')->nullable();
|
||||
$table->string('company_cert_number')->nullable();
|
||||
$table->string('contact_person_name')->nullable();
|
||||
$table->string('contact_person_id')->nullable();
|
||||
$table->string('email')->unique();
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->string('phone');
|
||||
$table->string('password');
|
||||
$table->string('status')->default('active');
|
||||
$table->string('preferred_language', 2)->default('ar');
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('consultations', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->date('booking_date')->index();
|
||||
$table->time('booking_time');
|
||||
$table->text('problem_summary');
|
||||
$table->string('consultation_type')->default('free');
|
||||
$table->decimal('payment_amount', 10, 2)->nullable();
|
||||
$table->string('payment_status')->default('na');
|
||||
$table->string('status')->default('pending');
|
||||
$table->text('admin_notes')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('user_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('consultations');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('timelines', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('case_name');
|
||||
$table->string('case_reference')->unique()->nullable();
|
||||
$table->string('status')->default('active');
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('user_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('timelines');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('timeline_updates', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('timeline_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('admin_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->text('update_text');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('timeline_updates');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('posts', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->json('title');
|
||||
$table->json('body');
|
||||
$table->string('status')->default('draft')->index();
|
||||
$table->timestamp('published_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('posts');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('working_hours', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->tinyInteger('day_of_week');
|
||||
$table->time('start_time');
|
||||
$table->time('end_time');
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('working_hours');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('blocked_times', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->date('block_date');
|
||||
$table->time('start_time')->nullable();
|
||||
$table->time('end_time')->nullable();
|
||||
$table->string('reason')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('blocked_times');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('notifications', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('type');
|
||||
$table->json('data');
|
||||
$table->timestamp('read_at')->nullable();
|
||||
$table->timestamp('sent_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('notifications');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('admin_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('admin_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->string('action');
|
||||
$table->string('target_type');
|
||||
$table->unsignedBigInteger('target_id')->nullable();
|
||||
$table->json('old_values')->nullable();
|
||||
$table->json('new_values')->nullable();
|
||||
$table->string('ip_address');
|
||||
$table->timestamp('created_at');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('admin_logs');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user