3 Commits

Author SHA1 Message Date
Mulanga
8bc6781e17 update readme
Some checks failed
CI / tests (push) Has been cancelled
CI / deploy-staging (push) Has been cancelled
CI / deploy-production (push) Has been cancelled
2026-03-12 18:02:56 +02:00
Mulanga
c936670573 update readme
Some checks failed
CI / tests (push) Has been cancelled
CI / deploy-staging (push) Has been cancelled
CI / deploy-production (push) Has been cancelled
2026-03-12 18:01:35 +02:00
2475daca4b fix: set assigned_by when syncing shift staff pivot records
Some checks failed
CI / tests (push) Has been cancelled
CI / deploy-staging (push) Has been cancelled
CI / deploy-production (push) Has been cancelled
2026-03-12 17:51:32 +02:00
7 changed files with 95 additions and 5 deletions

View File

@@ -28,10 +28,52 @@ A shift management application for scheduling staff, tracking attendance, and ge
## Quick Start ## Quick Start
### Prerequisites ## Prerequisites
- Docker & Docker Compose
### Setup - [Docker Desktop](https://www.docker.com/products/docker-desktop) installed
- [Docker Compose](https://docs.docker.com/compose/) (usually included with Docker Desktop)
## Quick Start
1. **Clone the repository:**
```sh
git clone <your-repo-url>
cd bhoza-shift-manager
```
2. **Copy the example environment file:**
```sh
cp src/.env.example src/.env
# Or manually create src/.env based on src/.env.example
```
3. **Start the app with MariaDB:**
```sh
docker-compose --profile mysql up -d
```
This will start the app, Nginx, MariaDB, Redis, and Mailpit containers.
4. **Install Composer dependencies:**
```sh
docker-compose exec app composer install
```
5. **Generate the application key:**
```sh
docker-compose exec app php artisan key:generate
```
6. **Run database migrations and seeders:**
```sh
docker-compose exec app php artisan migrate --seed
```
7. **Access the app:**
- Web: [http://localhost:8080](http://localhost:8080)
- Admin: [http://localhost:8080/admin/login](http://localhost:8080/admin/login)
- Mailpit: [http://localhost:8025](http://localhost:8025)
### Setup(Maybe you should run the one above 🤷🏿‍♂️)
```bash ```bash
git clone <repo-url> bhoza-shift-manager git clone <repo-url> bhoza-shift-manager

View File

@@ -56,7 +56,7 @@ public static function form(Form $form): Form
Forms\Components\Select::make('staffMembers') Forms\Components\Select::make('staffMembers')
->label('Assign Staff') ->label('Assign Staff')
->multiple() ->multiple()
->relationship('staff', 'name') ->options(User::query()->pluck('name', 'id'))
->preload() ->preload()
->searchable(), ->searchable(),
]) ])

View File

@@ -17,4 +17,17 @@ protected function mutateFormDataBeforeCreate(array $data): array
return $data; return $data;
} }
protected function afterCreate(): void
{
$staffIds = $this->data['staffMembers'] ?? [];
if (empty($staffIds)) {
return;
}
$this->record->staff()->syncWithPivotValues(
$staffIds,
['assigned_by' => auth()->id()]
);
}
} }

View File

@@ -54,4 +54,14 @@ protected function getHeaderActions(): array
->visible(fn () => $this->record->isPlanned()), ->visible(fn () => $this->record->isPlanned()),
]; ];
} }
protected function afterSave(): void
{
$staffIds = $this->data['staffMembers'] ?? [];
$this->record->staff()->syncWithPivotValues(
$staffIds,
['assigned_by' => auth()->id()]
);
}
} }

View File

@@ -31,7 +31,13 @@ public function table(Table $table): Table
Tables\Actions\AttachAction::make() Tables\Actions\AttachAction::make()
->label('Add Staff') ->label('Add Staff')
->preloadRecordSelect() ->preloadRecordSelect()
->visible(fn () => $this->getOwnerRecord()->isPlanned()), ->visible(fn () => $this->getOwnerRecord()->isPlanned())
->action(function (array $data, $ownerRecord) {
$staffId = $data['record'] ?? null;
if ($staffId) {
app(\App\Services\ShiftService::class)->assignStaff($ownerRecord, [$staffId]);
}
}),
]) ])
->actions([ ->actions([
Tables\Actions\DetachAction::make() Tables\Actions\DetachAction::make()

View File

@@ -29,6 +29,7 @@ public function createShift(array $data, ?array $staffIds = null): Shift
]); ]);
if ($staffIds) { if ($staffIds) {
logger()->info('Staff IDs:', $staffIds);
$this->assignStaff($shift, $staffIds); $this->assignStaff($shift, $staffIds);
} }
@@ -102,6 +103,11 @@ public function assignStaff(Shift $shift, array $staffIds): void
} }
$managerId = Auth::id(); $managerId = Auth::id();
if(!$managerId) {
throw new InvalidArgumentException('Authenticated user is required to assign staff.');
}
$syncData = []; $syncData = [];
foreach ($staffIds as $staffId) { foreach ($staffIds as $staffId) {

View File

@@ -13,11 +13,24 @@ class DatabaseSeeder extends Seeder
*/ */
public function run(): void public function run(): void
{ {
// Create the admin user
User::factory()->create([ User::factory()->create([
'name' => 'Admin User', 'name' => 'Admin User',
'email' => 'admin@example.com', 'email' => 'admin@example.com',
]); ]);
// Create 10 random staff users
User::factory()->create(['name' => 'Staff One', 'email' => 'staff1@example.com']);
User::factory()->create(['name' => 'Staff Two', 'email' => 'staff2@example.com']);
User::factory()->create(['name' => 'Staff Three', 'email' => 'staff3@example.com']);
User::factory()->create(['name' => 'Staff Four', 'email' => 'staff4@example.com']);
User::factory()->create(['name' => 'Staff Five', 'email' => 'staff5@example.com']);
User::factory()->create(['name' => 'Staff Six', 'email' => 'staff6@example.com']);
User::factory()->create(['name' => 'Staff Seven', 'email' => 'staff7@example.com']);
User::factory()->create(['name' => 'Staff Eight', 'email' => 'staff8@example.com']);
User::factory()->create(['name' => 'Staff Nine', 'email' => 'staff9@example.com']);
User::factory()->create(['name' => 'Staff Ten', 'email' => 'staff10@example.com']);
$this->call(RolePermissionSeeder::class); $this->call(RolePermissionSeeder::class);
} }
} }