├── .circleci └── config.yml ├── .env.example ├── .env.testing ├── .gitattributes ├── .gitignore ├── Procfile ├── app ├── AuditTrail.php ├── Console │ └── Kernel.php ├── Exceptions │ └── Handler.php ├── Http │ ├── Controllers │ │ ├── AdminController.php │ │ ├── Auth │ │ │ ├── ForgotPasswordController.php │ │ │ ├── LoginController.php │ │ │ ├── RegisterController.php │ │ │ └── ResetPasswordController.php │ │ ├── Controller.php │ │ ├── HomeController.php │ │ ├── MessageController.php │ │ ├── PayslipController.php │ │ ├── StaffController.php │ │ └── StaffLeaveController.php │ ├── Kernel.php │ ├── Middleware │ │ ├── CheckUserType.php │ │ ├── EncryptCookies.php │ │ ├── RedirectIfAuthenticated.php │ │ ├── TrimStrings.php │ │ └── VerifyCsrfToken.php │ └── Requests │ │ ├── AdminApproveRequest.php │ │ ├── CreateStaffRequest.php │ │ ├── EditStaffRequest.php │ │ ├── LeaveApplicationRequest.php │ │ ├── PayrollRequest.php │ │ └── SendMessageRequest.php ├── Interfaces │ └── RespondsToStaffCreated.php ├── Jobs │ ├── SendAdminLoginJob.php │ ├── SendLeaveStatusEmail.php │ ├── SendMessageJob.php │ └── SendPaySlipJob.php ├── Mail │ ├── EmailStaff.php │ ├── LeaveStatusChanged.php │ ├── SendAdminLoginDetails.php │ └── SendPayslipEmail.php ├── Message.php ├── Observers │ ├── AdminObserver.php │ ├── MessageObserver.php │ ├── PayrollObserver.php │ └── StaffObserver.php ├── Payroll.php ├── Providers │ ├── AppServiceProvider.php │ ├── AuthServiceProvider.php │ ├── BroadcastServiceProvider.php │ ├── EventServiceProvider.php │ └── RouteServiceProvider.php ├── Repositories │ ├── HomeRepository.php │ ├── LeaveManagementRepository.php │ ├── MessageRepository.php │ ├── PayrollRepository.php │ ├── StaffProfileImageRepository.php │ ├── StaffRepository.php │ └── UserRepository.php ├── Staff.php ├── StaffLeave.php ├── User.php └── helpers.php ├── artisan ├── bootstrap ├── app.php ├── autoload.php └── cache │ └── .gitignore ├── composer.json ├── composer.lock ├── config ├── app.php ├── auth.php ├── broadcasting.php ├── cache.php ├── database.php ├── filesystems.php ├── mail.php ├── queue.php ├── services.php ├── session.php └── view.php ├── database ├── .gitignore ├── factories │ └── ModelFactory.php ├── migrations │ ├── 2014_10_12_000000_create_users_table.php │ ├── 2014_10_12_100000_create_password_resets_table.php │ ├── 2017_08_28_173952_create_staff_table.php │ ├── 2018_12_14_070056_create_audit_trails_table.php │ ├── 2018_12_14_073918_create_jobs_table.php │ ├── 2018_12_14_081558_create_messages_table.php │ ├── 2018_12_19_105306_create_payrolls_table.php │ └── 2019_01_03_233410_create_staff_leaves_table.php └── seeds │ ├── DatabaseSeeder.php │ ├── StaffLeaveTableSeeder.php │ ├── StaffTableSeeder.php │ └── UsersTableSeeder.php ├── package.json ├── phpunit.xml ├── public ├── .htaccess ├── css │ ├── app.css │ ├── bootstrap.css │ ├── font-awesome.min.css │ ├── staff-profile.css │ └── styles.css ├── favicon.ico ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ ├── fontawesome-webfont.woff2 │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── index.php ├── js │ ├── app.js │ ├── bootstrap.min.js │ └── jquery.min.js ├── less │ ├── animated.less │ ├── bordered-pulled.less │ ├── core.less │ ├── fixed-width.less │ ├── font-awesome.less │ ├── icons.less │ ├── larger.less │ ├── list.less │ ├── mixins.less │ ├── path.less │ ├── rotated-flipped.less │ ├── screen-reader.less │ ├── stacked.less │ └── variables.less ├── robots.txt ├── scss │ ├── _animated.scss │ ├── _bordered-pulled.scss │ ├── _core.scss │ ├── _fixed-width.scss │ ├── _icons.scss │ ├── _larger.scss │ ├── _list.scss │ ├── _mixins.scss │ ├── _path.scss │ ├── _rotated-flipped.scss │ ├── _screen-reader.scss │ ├── _stacked.scss │ ├── _variables.scss │ └── font-awesome.scss └── web.config ├── readme.md ├── resources ├── assets │ ├── js │ │ ├── app.js │ │ ├── bootstrap.js │ │ └── components │ │ │ └── Example.vue │ └── sass │ │ ├── _variables.scss │ │ └── app.scss ├── lang │ └── en │ │ ├── auth.php │ │ ├── pagination.php │ │ ├── passwords.php │ │ └── validation.php └── views │ ├── admin-home.blade.php │ ├── all-admin-members.blade.php │ ├── all-staff-members.blade.php │ ├── all-staff-payrolls.blade.php │ ├── apply-leave.blade.php │ ├── auth │ ├── login.blade.php │ ├── passwords │ │ ├── email.blade.php │ │ └── reset.blade.php │ └── register.blade.php │ ├── create-payslip.blade.php │ ├── edit-staff-member.blade.php │ ├── emails │ ├── admin-login.blade.php │ ├── email-leave-status.blade.php │ ├── email-pay-slip.blade.php │ └── message.blade.php │ ├── layouts │ ├── admin.blade.php │ └── app.blade.php │ ├── leaves.blade.php │ ├── message.blade.php │ ├── new-staff.blade.php │ ├── parts │ ├── action-buttons.blade.php │ └── message-block.blade.php │ ├── staff-show.blade.php │ ├── user-leaves.blade.php │ └── welcome.blade.php ├── routes ├── api.php ├── channels.php ├── console.php └── web.php ├── server.php ├── storage ├── app │ ├── .gitignore │ └── public │ │ └── .gitignore ├── framework │ ├── .gitignore │ ├── cache │ │ └── .gitignore │ ├── sessions │ │ └── .gitignore │ ├── testing │ │ └── .gitignore │ └── views │ │ └── .gitignore └── logs │ └── .gitignore ├── tests ├── CreatesApplication.php ├── Feature │ ├── LeaveManagementTest.php │ ├── PayrollTest.php │ ├── StaffTest.php │ └── UserTest.php ├── TestCase.php └── Unit │ ├── ExampleTest.php │ ├── SendGeneralMessageToStaffTest.php │ └── SendPayslipTest.php └── webpack.mix.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # PHP CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-php/ for more details 4 | # 5 | version: 2 6 | jobs: 7 | build: 8 | docker: 9 | # specify the version you desire here 10 | - image: circleci/php:7.1-browsers 11 | 12 | # Specify service dependencies here if necessary 13 | # CircleCI maintains a library of pre-built images 14 | # documented at https://circleci.com/docs/2.0/circleci-images/ 15 | # - image: circleci/mysql:9.4 16 | 17 | working_directory: ~/repo 18 | 19 | steps: 20 | - run: sudo apt-get update && sudo apt-get install -y libpng-dev libjpeg62-turbo-dev 21 | - checkout 22 | 23 | - run: 24 | name: Install PHP Extensions 25 | command: sudo docker-php-ext-install gd exif 26 | 27 | # Download and cache dependencies 28 | - restore_cache: 29 | keys: 30 | - v1-dependencies-{{ checksum "composer.json" }} 31 | # fallback to using the latest cache if no exact match is found 32 | - v1-dependencies- 33 | 34 | - run: composer install -n --prefer-dist 35 | 36 | - save_cache: 37 | paths: 38 | - ./vendor 39 | key: v1-dependencies-{{ checksum "composer.json" }} 40 | 41 | - run: 42 | name: Setup Laravel testing environment variables for CircleCI test 43 | command: cp .env.testing .env 44 | 45 | - run: 46 | name: Update composer to latest version 47 | command: composer self-update 48 | 49 | - restore_cache: 50 | keys: 51 | - composer-v1-{{ checksum "composer.json" }} 52 | - composer-v1- 53 | 54 | - run: composer install -n --prefer-dist --ignore-platform-reqs 55 | 56 | - save_cache: 57 | key: composer-v1-{{ checksum "composer.json" }} 58 | paths: 59 | - vendor 60 | 61 | - run: 62 | name: Create SQLite Database 63 | command: touch database/testing.sqlite 64 | 65 | - run: 66 | name: Migrate Laravel Database 67 | command: php artisan migrate --env=testing --force 68 | 69 | - run: 70 | name: Test 1 - Run Phpunit for Server-Side HTTP Requests & PHP Unit Testing 71 | command: vendor/bin/phpunit -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME="Staff Management App" 2 | APP_ENV=local 3 | APP_KEY=base64:je2GyMDcKm8R1wC3D046jCVhg0Wb0Pi63p0A2gSIoOc= 4 | APP_DEBUG=true 5 | APP_LOG_LEVEL=debug 6 | APP_URL=http://staff-management-system.test 7 | 8 | DB_CONNECTION=pgsql 9 | DB_HOST=127.0.0.1 10 | DB_PORT=5432 11 | DB_DATABASE=staff_db 12 | DB_USERNAME=root 13 | DB_PASSWORD=root 14 | 15 | BROADCAST_DRIVER=log 16 | CACHE_DRIVER=file 17 | SESSION_DRIVER=file 18 | QUEUE_DRIVER=database 19 | 20 | REDIS_HOST=127.0.0.1 21 | REDIS_PASSWORD=null 22 | REDIS_PORT=6379 23 | 24 | 25 | PUSHER_APP_ID= 26 | PUSHER_APP_KEY= 27 | PUSHER_APP_SECRET= 28 | 29 | 30 | 31 | MAIL_DRIVER=smtp 32 | MAIL_HOST=smtp.sendgrid.net 33 | MAIL_PORT=587 34 | MAIL_USERNAME= 35 | MAIL_PASSWORD= 36 | MAIL_ENCRYPTION=tls 37 | MAIL_FROM_NAME="Admin Staff Management" 38 | MAIL_FROM_ADDRESS=info@staff.com 39 | 40 | ACCRUED_LEAVE_DAYS_IN_A_MONTH=1.5 41 | 42 | -------------------------------------------------------------------------------- /.env.testing: -------------------------------------------------------------------------------- 1 | APP_NAME="Staff Management App" 2 | APP_ENV=testing 3 | APP_KEY=base64:je2GyMDcKm8R1wC3D046jCVhg0Wb0Pi63p0A2gSIoOc= 4 | APP_DEBUG=true 5 | APP_LOG_LEVEL=debug 6 | APP_URL=http://staff-management-system.test 7 | 8 | DB_CONNECTION=sqlite_testing 9 | 10 | 11 | BROADCAST_DRIVER=log 12 | CACHE_DRIVER=file 13 | SESSION_DRIVER=file 14 | QUEUE_DRIVER=database 15 | 16 | REDIS_HOST=127.0.0.1 17 | REDIS_PASSWORD=null 18 | REDIS_PORT=6379 19 | 20 | 21 | PUSHER_APP_ID= 22 | PUSHER_APP_KEY= 23 | PUSHER_APP_SECRET= 24 | 25 | 26 | 27 | 28 | 29 | MAIL_DRIVER=log 30 | MAIL_HOST=smtp.sendgrid.net 31 | MAIL_PORT=587 32 | MAIL_USERNAME=pollafrique 33 | MAIL_PASSWORD=pollafrique2016 34 | MAIL_ENCRYPTION=tls 35 | MAIL_FROM_NAME="Admin Staff Management" 36 | MAIL_FROM_ADDRESS=info@staff.com 37 | 38 | 39 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.css linguist-vendored 3 | *.scss linguist-vendored 4 | *.js linguist-vendored 5 | CHANGELOG.md export-ignore 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /public/hot 3 | /public/storage 4 | /storage/*.key 5 | /vendor 6 | /.idea 7 | /.vagrant 8 | Homestead.json 9 | Homestead.yaml 10 | npm-debug.log 11 | yarn-error.log 12 | .env 13 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: vendor/bin/heroku-php-apache2 public 2 | worker: php artisan queue:work database --daemon -------------------------------------------------------------------------------- /app/AuditTrail.php: -------------------------------------------------------------------------------- 1 | command('inspire') 28 | // ->hourly(); 29 | } 30 | 31 | /** 32 | * Register the Closure based commands for the application. 33 | * 34 | * @return void 35 | */ 36 | protected function commands() 37 | { 38 | require base_path('routes/console.php'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/Exceptions/Handler.php: -------------------------------------------------------------------------------- 1 | expectsJson()) { 60 | return response()->json(['error' => 'Unauthenticated.'], 401); 61 | } 62 | 63 | return redirect()->guest(route('login')); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/Http/Controllers/AdminController.php: -------------------------------------------------------------------------------- 1 | user_repository = $user_repository; 20 | } 21 | 22 | 23 | public function index() 24 | { 25 | $admins = User::simplePaginate(50); 26 | return view('all-admin-members', compact('admins')); 27 | } 28 | 29 | 30 | 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/ForgotPasswordController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/LoginController.php: -------------------------------------------------------------------------------- 1 | middleware('guest')->except('logout'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/RegisterController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 40 | } 41 | 42 | /** 43 | * Get a validator for an incoming registration request. 44 | * 45 | * @param array $data 46 | * @return \Illuminate\Contracts\Validation\Validator 47 | */ 48 | protected function validator(array $data) 49 | { 50 | return Validator::make($data, [ 51 | 'name' => 'required|string|max:255', 52 | 'email' => 'required|string|email|max:255|unique:users', 53 | 'password' => 'required|string|min:6|confirmed', 54 | ]); 55 | } 56 | 57 | /** 58 | * Create a new user instance after a valid registration. 59 | * 60 | * @param array $data 61 | * @return \App\User 62 | */ 63 | protected function create(array $data) 64 | { 65 | return User::create([ 66 | 'name' => $data['name'], 67 | 'email' => $data['email'], 68 | 'password' => bcrypt($data['password']), 69 | ]); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/ResetPasswordController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | middleware('auth'); 21 | $this->home_repository = $home_repository; 22 | } 23 | 24 | /** 25 | * Show the application dashboard. 26 | * 27 | * @return \Illuminate\Http\Response 28 | */ 29 | public function index() 30 | { 31 | return $this->home_repository->userVisitHomePage(); 32 | } 33 | 34 | 35 | 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/Http/Controllers/MessageController.php: -------------------------------------------------------------------------------- 1 | message_repository = $message_repository; 17 | } 18 | 19 | public function createMessage(Staff $staff){ 20 | $staff = Staff::with('user')->whereId($staff->id)->first(); 21 | return view('message',compact('staff')); 22 | } 23 | 24 | public function sendMessage(SendMessageRequest $sendMessageRequest){ 25 | return $this->message_repository->sendGeneralMessage($sendMessageRequest); 26 | } 27 | 28 | public function sendStaffPayroll(Staff $staff, Payroll $payroll){ 29 | return $this->message_repository->sendStaffPayrollMessage($staff,$payroll); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/Http/Controllers/PayslipController.php: -------------------------------------------------------------------------------- 1 | payslip = $payslip; 24 | $this->message_repository = $messageRepository; 25 | } 26 | 27 | public function index(){ 28 | $payrolls = Payroll::with("staff.user")->get(); 29 | return view("all-staff-payrolls", compact('payrolls')); 30 | } 31 | 32 | public function create(Staff $staff){ 33 | return view('create-payslip', compact('staff')); 34 | } 35 | 36 | public function store(PayrollRequest $request) 37 | { 38 | return $this->payslip->createPayslip($request, $this); 39 | } 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/Http/Controllers/StaffController.php: -------------------------------------------------------------------------------- 1 | middleware('auth'); 19 | $this->staff_repository = $staff_repository; 20 | } 21 | 22 | 23 | public function create() 24 | { 25 | return view('new-staff'); 26 | } 27 | 28 | public function index() 29 | { 30 | $staff = $this->staff_repository->getAllStaff(); 31 | return view('all-staff-members', compact('staff')); 32 | } 33 | 34 | public function edit($staff_id) 35 | { 36 | $staff = Staff::with('user')->find($staff_id); 37 | return view('edit-staff-member', compact('staff')); 38 | } 39 | 40 | 41 | public function store(CreateStaffRequest $request) 42 | { 43 | return $this->staff_repository->createStaff($request, $this); 44 | } 45 | 46 | public function show(Staff $staff){ 47 | return $this->staff_repository->getOneStaff($staff); 48 | } 49 | 50 | public function delete($staff_id) 51 | { 52 | return $this->staff_repository->deleteStaff($staff_id); 53 | } 54 | 55 | 56 | public function update(EditStaffRequest $request, $staff_id) 57 | { 58 | return $this->staff_repository->updateStaffProfile($request,$staff_id, $this); 59 | } 60 | 61 | 62 | public function successfulResponse($message = 'New Staff Added to the company’s database') 63 | { 64 | return redirect()->route('all-staff-members')->with('message', $message); 65 | } 66 | 67 | public function unSuccessfulResponse($message = "Unable to create staff") 68 | { 69 | return redirect()->back()->with('err', $message); 70 | } 71 | 72 | 73 | 74 | } 75 | -------------------------------------------------------------------------------- /app/Http/Controllers/StaffLeaveController.php: -------------------------------------------------------------------------------- 1 | leave_management_repository = $leave_management_repository; 19 | } 20 | 21 | public function create(){ 22 | return view("apply-leave"); 23 | } 24 | 25 | public function store(LeaveApplicationRequest $request){ 26 | return $this->leave_management_repository->applyForLeave($request); 27 | } 28 | 29 | public function staffLeaves(Staff $staff){ 30 | $leaves = $this->leave_management_repository->getAStaffLeave($staff); 31 | return view("user-leaves", compact('leaves')); 32 | } 33 | 34 | 35 | public function allPendingLeave(){ 36 | $leaves = $this->leave_management_repository->getAllPendingLeave(); 37 | return view('leaves', compact('leaves'))->with(['leave_type' => 'Pending Leaves']); 38 | } 39 | 40 | public function allApprovedLeave(){ 41 | $leaves = $this->leave_management_repository->getAllApprovedLeave(); 42 | return view('leaves', compact('leaves'))->with(['leave_type' => 'Approved Leaves']); 43 | } 44 | 45 | public function approveLeave(AdminApproveRequest $request){ 46 | return $this->leave_management_repository->adminApproveLeave($request); 47 | } 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/Http/Kernel.php: -------------------------------------------------------------------------------- 1 | [ 31 | \App\Http\Middleware\EncryptCookies::class, 32 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, 33 | \Illuminate\Session\Middleware\StartSession::class, 34 | // \Illuminate\Session\Middleware\AuthenticateSession::class, 35 | \Illuminate\View\Middleware\ShareErrorsFromSession::class, 36 | \App\Http\Middleware\VerifyCsrfToken::class, 37 | \Illuminate\Routing\Middleware\SubstituteBindings::class, 38 | ], 39 | 40 | 'api' => [ 41 | 'throttle:60,1', 42 | 'bindings', 43 | ], 44 | ]; 45 | 46 | /** 47 | * The application's route middleware. 48 | * 49 | * These middleware may be assigned to groups or used individually. 50 | * 51 | * @var array 52 | */ 53 | protected $routeMiddleware = [ 54 | 'auth' => \Illuminate\Auth\Middleware\Authenticate::class, 55 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 56 | 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 57 | 'can' => \Illuminate\Auth\Middleware\Authorize::class, 58 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 59 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 60 | 'user.type' => CheckUserType::class, 61 | ]; 62 | } 63 | -------------------------------------------------------------------------------- /app/Http/Middleware/CheckUserType.php: -------------------------------------------------------------------------------- 1 | is_admin != true) { 20 | 21 | return redirect('home'); 22 | 23 | } 24 | 25 | return $next($request); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/Http/Middleware/EncryptCookies.php: -------------------------------------------------------------------------------- 1 | check()) { 21 | return redirect('/home'); 22 | } 23 | 24 | return $next($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrimStrings.php: -------------------------------------------------------------------------------- 1 | is_admin == true) { 18 | return true; 19 | } 20 | return false; 21 | } 22 | 23 | 24 | /** 25 | * Get the validation rules that apply to the request. 26 | * 27 | * @return array 28 | */ 29 | public function rules() 30 | { 31 | return [ 32 | 'leave_id' => 'required' 33 | ]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/Http/Requests/CreateStaffRequest.php: -------------------------------------------------------------------------------- 1 | 'required|max:255', 28 | 'email' => 'required|email|max:255|unique:users', 29 | 'image' => 'required|mimes:jpg,tiff,png,svg,gif,bmp,jpeg|max:10240', 30 | 'address' => 'max:255', 31 | 'level' => 'required', 32 | 'city' => 'required', 33 | 'age' => 'required', 34 | 'phone' => 'required', 35 | 'state' => 'required', 36 | 'country' => 'required', 37 | 'start_work_date' => 'required', 38 | ]; 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /app/Http/Requests/EditStaffRequest.php: -------------------------------------------------------------------------------- 1 | 'required|max:255|string', 28 | 'level' => 'required', 29 | 'email' => 'required|email|max:255', 30 | 'phone' => 'required|string', 31 | 'address' => 'string|max:255', 32 | 'user_id' => 'required', 33 | ]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/Http/Requests/LeaveApplicationRequest.php: -------------------------------------------------------------------------------- 1 | 'required', 29 | 'leave_start_date' => 'required|date|after:today', 30 | 'leave_end_date' => 'required|date|after:leave_start_date', 31 | 'user_id' => 'required', 32 | ]; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/Http/Requests/PayrollRequest.php: -------------------------------------------------------------------------------- 1 | 'required', 28 | 'gross_salary' => 'required|numeric', 29 | 'tax_percentage' => 'required|numeric', 30 | 'month' => 'required', 31 | 'year' => 'required' 32 | ]; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/Http/Requests/SendMessageRequest.php: -------------------------------------------------------------------------------- 1 | 'required', 28 | 'subject' => 'required', 29 | 'content' => 'required' 30 | ]; 31 | } 32 | 33 | 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/Interfaces/RespondsToStaffCreated.php: -------------------------------------------------------------------------------- 1 | admin = $user; 29 | $this->password = $password; 30 | } 31 | 32 | /** 33 | * Execute the job. 34 | * 35 | * @return void 36 | */ 37 | public function handle() 38 | { 39 | Mail::to($this->admin)->send(new SendAdminLoginDetails($this->admin,$this->password)); 40 | } 41 | 42 | 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/Jobs/SendLeaveStatusEmail.php: -------------------------------------------------------------------------------- 1 | staff = $staff; 30 | $this->leave = $leave; 31 | } 32 | 33 | 34 | /** 35 | * Execute the job. 36 | * 37 | * @return void 38 | */ 39 | public function handle() 40 | { 41 | Mail::to($this->staff->user->email)->send(new LeaveStatusChanged($this->staff,$this->leave)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/Jobs/SendMessageJob.php: -------------------------------------------------------------------------------- 1 | staff = $staff; 30 | $this->content = $message; 31 | } 32 | 33 | /** 34 | * Execute the job. 35 | * 36 | * @return void 37 | */ 38 | public function handle() 39 | { 40 | Mail::to($this->staff->user->email)->send(new EmailStaff($this->staff,$this->content)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/Jobs/SendPaySlipJob.php: -------------------------------------------------------------------------------- 1 | staff = $staff; 32 | $this->content = $message; 33 | $this->payroll = $payroll; 34 | } 35 | 36 | /** 37 | * Execute the job. 38 | * 39 | * @return void 40 | */ 41 | public function handle() 42 | { 43 | Mail::to($this->staff->user->email)->send(new SendPayslipEmail($this->staff,$this->content, $this->payroll)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/Mail/EmailStaff.php: -------------------------------------------------------------------------------- 1 | staff = $staff; 27 | $this->content = $message; 28 | } 29 | 30 | /** 31 | * Build the message. 32 | * 33 | * @return $this 34 | */ 35 | public function build() 36 | { 37 | return $this->view('emails.message') 38 | ->to($this->staff->user->email) 39 | ->subject($this->content->subject); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/Mail/LeaveStatusChanged.php: -------------------------------------------------------------------------------- 1 | staff = $staff; 26 | $this->leave = $leave; 27 | } 28 | 29 | /** 30 | * Build the message. 31 | * 32 | * @return $this 33 | */ 34 | public function build() 35 | { 36 | return $this->view('emails.email-leave-status') 37 | ->to($this->staff->user->email) 38 | ->subject('Status of your leave application'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/Mail/SendAdminLoginDetails.php: -------------------------------------------------------------------------------- 1 | admin = $admin; 27 | $this->password = $password; 28 | } 29 | 30 | /** 31 | * Build the message. 32 | * 33 | * @return $this 34 | */ 35 | public function build() 36 | { 37 | return $this->view('emails.admin-login') 38 | ->subject("Your Login Details"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/Mail/SendPayslipEmail.php: -------------------------------------------------------------------------------- 1 | staff = $staff; 29 | $this->content = $message; 30 | $this->payroll = $payroll; 31 | } 32 | 33 | /** 34 | * Build the message. 35 | * 36 | * @return $this 37 | */ 38 | public function build() 39 | { 40 | return $this->view('emails.email-pay-slip') 41 | ->to($this->staff->user->email) 42 | ->subject($this->content->subject); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/Message.php: -------------------------------------------------------------------------------- 1 | belongsTo(User::class, 'sender_id'); 14 | } 15 | 16 | public function staff(){ 17 | return $this->belongsTo(Staff::class, 'recipient_id'); 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /app/Observers/AdminObserver.php: -------------------------------------------------------------------------------- 1 | $user->id, 30 | 'resource_type_affected' => 'admin', 31 | 'affected_resource_id' => $user->id, 32 | 'trail_activity_details' => 'Admin '.$user->name.' was added as an administrator on '.$user->created_at.' by '.auth()->user()->name, 33 | ]); 34 | } 35 | 36 | 37 | /** 38 | * Listen to the User deleting event. 39 | * 40 | * @param User $user 41 | * @return void 42 | */ 43 | public function updated(User $user) 44 | { 45 | AuditTrail::create([ 46 | 'admin_id' => $user->id, 47 | 'resource_type_affected' => 'admin', 48 | 'affected_resource_id' => $user->id, 49 | 'trail_activity_details' => 'Admin '.$user->name.' Just log into the app on ', 50 | ]); 51 | 52 | } 53 | 54 | /** 55 | * Listen to the User deleting event. 56 | * 57 | * @param User $user 58 | * @return void 59 | */ 60 | public function deleting(User $user) 61 | { 62 | // 63 | } 64 | 65 | 66 | 67 | 68 | 69 | 70 | } -------------------------------------------------------------------------------- /app/Observers/MessageObserver.php: -------------------------------------------------------------------------------- 1 | where('id', $message->id)->first(); 29 | 30 | $create_audit_trail = AuditTrail::create([ 31 | 'admin_id' => auth()->id(), 32 | 'recipient_id' => $message->staff->id, 33 | 'resource_type_affected' => 'messaging', 34 | 'affected_resource_id' => $message->id, 35 | 'trail_activity_details' => 'Admin '.Auth::user()->name.' sent message to staff '.$message->staff->name.' on '.$message->created_at, 36 | ]); 37 | 38 | } 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | } -------------------------------------------------------------------------------- /app/Observers/PayrollObserver.php: -------------------------------------------------------------------------------- 1 | where('id',$payroll->id )->first(); 29 | $create_audit_trail = AuditTrail::create([ 30 | 'admin_id' =>auth()->id(), 31 | 'resource_type_affected' => 'payroll', 32 | 'affected_resource_id' => $payroll->id, 33 | 'trail_activity_details' => 'Payslip was generated for '.$payroll->staff->name.' on'.$payroll->created_at.' by '.auth()->user()->name, 34 | ]); 35 | } 36 | 37 | 38 | /** 39 | * Listen to the User deleting event. 40 | * 41 | * @param User $user 42 | * @return void 43 | */ 44 | // public function updated(Payroll $user) 45 | // { 46 | //// $time = Carbon::now(); 47 | //// $user->updated_at = $time; 48 | //// $user->save(); 49 | // 50 | // $create_audit_trail = AuditTrail::create([ 51 | // 'admin_id' => $user->id, 52 | // 'resource_type_affected' => 'admin', 53 | // 'affected_resource_id' => $user->id, 54 | // 'trail_activity_details' => 'Admin '.$user->name.' Just log into the app on ', 55 | // ]); 56 | // 57 | // } 58 | 59 | 60 | 61 | /** 62 | * Listen to the User deleting event. 63 | * 64 | * @param User $user 65 | * @return void 66 | */ 67 | public function deleting(Payroll $payroll) 68 | { 69 | // 70 | } 71 | 72 | 73 | 74 | } -------------------------------------------------------------------------------- /app/Observers/StaffObserver.php: -------------------------------------------------------------------------------- 1 | auth()->id(), 31 | 'resource_type_affected' => 'staff', 32 | 'affected_resource_id' => $staff->id, 33 | 'trail_activity_details' => 'Admin '.Auth::user()->name.' Just created staff with name '.$staff->name.' on '.$staff->created_at, 34 | ]); 35 | 36 | } 37 | 38 | 39 | /** 40 | * Listen to the User deleting event. 41 | * 42 | * @param Staff $staff 43 | * @return void 44 | */ 45 | public function updated(Staff $staff) 46 | { 47 | $create_audit_trail = AuditTrail::create([ 48 | 'admin_id' => auth()->id(), 49 | 'resource_type_affected' => 'staff', 50 | 'affected_resource_id' => $staff->id, 51 | 'trail_activity_details' => 'Admin '.Auth::user()->name.' Just edited staff with name '.$staff->name.' on '.$staff->created_at, 52 | ]); 53 | } 54 | 55 | /** 56 | * Listen to the User deleting event. 57 | * 58 | * @param Staff $staff 59 | * @return void 60 | */ 61 | public function deleting(Staff $staff) 62 | { 63 | $create_audit_trail = AuditTrail::create([ 64 | 'admin_id' => auth()->id(), 65 | 'resource_type_affected' => 'staff', 66 | 'affected_resource_id' => $staff->id, 67 | 'trail_activity_details' => 'Admin '.Auth::user()->name.' Just deleted staff with name '.$staff->name.' on '.$staff->created_at, 68 | ]); 69 | 70 | } 71 | 72 | 73 | 74 | 75 | 76 | } -------------------------------------------------------------------------------- /app/Payroll.php: -------------------------------------------------------------------------------- 1 | belongsTo(Staff::class, 'staff_id'); 15 | } 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | 'App\Policies\ModelPolicy', 17 | ]; 18 | 19 | /** 20 | * Register any authentication / authorization services. 21 | * 22 | * @return void 23 | */ 24 | public function boot() 25 | { 26 | $this->registerPolicies(); 27 | 28 | // 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/Providers/BroadcastServiceProvider.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'App\Listeners\EventListener', 18 | ], 19 | ]; 20 | 21 | /** 22 | * Register any events for your application. 23 | * 24 | * @return void 25 | */ 26 | public function boot() 27 | { 28 | parent::boot(); 29 | 30 | // 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Providers/RouteServiceProvider.php: -------------------------------------------------------------------------------- 1 | mapApiRoutes(); 39 | 40 | $this->mapWebRoutes(); 41 | 42 | // 43 | } 44 | 45 | /** 46 | * Define the "web" routes for the application. 47 | * 48 | * These routes all receive session state, CSRF protection, etc. 49 | * 50 | * @return void 51 | */ 52 | protected function mapWebRoutes() 53 | { 54 | Route::middleware('web') 55 | ->namespace($this->namespace) 56 | ->group(base_path('routes/web.php')); 57 | } 58 | 59 | /** 60 | * Define the "api" routes for the application. 61 | * 62 | * These routes are typically stateless. 63 | * 64 | * @return void 65 | */ 66 | protected function mapApiRoutes() 67 | { 68 | Route::prefix('api') 69 | ->middleware('api') 70 | ->namespace($this->namespace) 71 | ->group(base_path('routes/api.php')); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/Repositories/HomeRepository.php: -------------------------------------------------------------------------------- 1 | get(); 20 | if (Auth::user()->is_admin == false ) { 21 | $recent_activities = AuditTrail::where('resource_type_affected', 'admin')->where('affected_resource_id', Auth::user()->id)->latest()->get(); 22 | } 23 | return view('admin-home', compact('recent_activities')); 24 | } 25 | 26 | 27 | } -------------------------------------------------------------------------------- /app/Repositories/LeaveManagementRepository.php: -------------------------------------------------------------------------------- 1 | message_repository = $messageRepository; 24 | } 25 | 26 | public function applyForLeave(Request $request){ 27 | 28 | $staff = Staff::find($request->get('user_id')); 29 | $outstanding_leave_days = $staff->getOutStandingLeaveDays(); 30 | $number_of_leave_days_applying_for = $this->getNumberOfLeaveDaysApplyingFor($request); 31 | if ($number_of_leave_days_applying_for > $outstanding_leave_days) { 32 | return redirect()->back()->with([ 33 | 'message' => "number of leave days you're applying for (".$number_of_leave_days_applying_for.") is greater than your outstanding leave days (".$outstanding_leave_days.")" 34 | ]); 35 | } 36 | 37 | $leave_details = $this->buildLeaveRequestDetails($request, $staff); 38 | $create_staff_leave = StaffLeave::create($leave_details); 39 | return redirect()->route("my-leave", $create_staff_leave->staff_id); 40 | } 41 | 42 | 43 | public function getAStaffLeave(Staff $staff) 44 | { 45 | return Staff::with('user','leaves')->where('id', $staff->id)->first(); 46 | } 47 | 48 | 49 | public function getAllPendingLeave() 50 | { 51 | return StaffLeave::with('staff.user')->where('is_approved', false)->get(); 52 | } 53 | 54 | public function getAllApprovedLeave() 55 | { 56 | return StaffLeave::with('staff.user')->where('is_approved', true)->get(); 57 | } 58 | 59 | public function adminApproveLeave(Request $request) 60 | { 61 | $approve_leave = StaffLeave::where('id', $request->get('leave_id'))->update(['is_approved' => true]); 62 | 63 | if ($approve_leave) { 64 | $leave = StaffLeave::find($request->get('leave_id')); 65 | $staff = Staff::with('user')->find($leave->staff_id); 66 | SendLeaveStatusEmail::dispatch($staff,$leave); 67 | } 68 | 69 | return redirect()->route('approved-leave'); 70 | } 71 | 72 | 73 | 74 | /** 75 | * @param Request $request 76 | * @return int 77 | */ 78 | private function getNumberOfLeaveDaysApplyingFor(Request $request) 79 | { 80 | $leave_start_date = Carbon::parse($request->get('leave_start_date')); 81 | $leave_end_date = Carbon::parse($request->get('leave_end_date')); 82 | $number_of_leave_days_applying_for = getNumberOfWeekDaysBetweenTwoDates($leave_start_date, $leave_end_date); 83 | return $number_of_leave_days_applying_for; 84 | } 85 | 86 | /** 87 | * @param Request $request 88 | * @param $staff 89 | * @return array 90 | */ 91 | private function buildLeaveRequestDetails(Request $request, $staff) 92 | { 93 | $leave_details = $request->except('token', 'user_id'); 94 | $leave_details = array_add($leave_details, 'staff_id', $staff->id); 95 | return $leave_details; 96 | } 97 | 98 | 99 | } -------------------------------------------------------------------------------- /app/Repositories/MessageRepository.php: -------------------------------------------------------------------------------- 1 | find($sendMessageRequest->get('id')); 28 | $create_message = $this->createGeneralMessage($sendMessageRequest, $staff); 29 | if ($create_message) { 30 | SendMessageJob::dispatch($staff,$create_message); 31 | return redirect()->route('all-staff-members'); 32 | } 33 | return redirect()->back(); 34 | } 35 | 36 | /** 37 | * @param Request $sendMessageRequest 38 | * @param $staff 39 | * @return mixed 40 | */ 41 | private function createGeneralMessage(Request $sendMessageRequest, $staff) 42 | { 43 | $create_message = Message::create([ 44 | 'sender_id' => auth()->id(), 45 | 'recipient_id' => $staff->id, 46 | 'subject' => $sendMessageRequest->get('subject'), 47 | 'content' => $sendMessageRequest->get('content') 48 | ]); 49 | return $create_message; 50 | } 51 | 52 | 53 | 54 | public function sendStaffPayrollMessage(Staff $staff, Payroll $payroll){ 55 | 56 | $staff = Staff::with('user')->whereId($staff->id)->first(); 57 | $payroll = Payroll::with('staff.user')->whereId($payroll->id)->first(); 58 | $create_message = $this->createStaffPayrollMessage($staff, $payroll); 59 | 60 | if ($create_message) { 61 | SendPaySlipJob::dispatch($staff,$create_message,$payroll); 62 | return redirect()->route('all-staff-members-payroll'); 63 | } 64 | return redirect()->back(); 65 | } 66 | 67 | /** 68 | * @param Staff $staff 69 | * @param Payroll $payroll 70 | * @return Message|\Illuminate\Database\Eloquent\Model 71 | */ 72 | private function createStaffPayrollMessage(Staff $staff, Payroll $payroll) 73 | { 74 | $create_message = Message::create([ 75 | 'sender_id' => auth()->id(), 76 | 'recipient_id' => $payroll->staff->id, 77 | 'subject' => "Your Invoice for " . $payroll->month . " " . $payroll->year, 78 | 'content' => "Invoice sent to " . $staff->name . " for " . $payroll->month . " " . $payroll->year, 79 | ]); 80 | return $create_message; 81 | } 82 | 83 | 84 | 85 | 86 | 87 | } -------------------------------------------------------------------------------- /app/Repositories/PayrollRepository.php: -------------------------------------------------------------------------------- 1 | message_repository = $messageRepository; 25 | } 26 | 27 | public function createPayslip(Request $request, PayslipController $payrollController){ 28 | $staff = Staff::with('user')->where('id', $request->get('staff_id'))->first(); 29 | $create_payroll_details = $this->buildPayslipProperties($request); 30 | $create_payroll = Payroll::create($create_payroll_details); 31 | 32 | if ($create_payroll) { 33 | $this->message_repository->sendStaffPayrollMessage($staff, $create_payroll); 34 | return redirect()->route("all-staff-members-payroll"); 35 | } 36 | return redirect()->back(); 37 | } 38 | 39 | 40 | /** 41 | * @param Request $request 42 | * @return array 43 | */ 44 | public function buildPayslipProperties(Request $request) 45 | { 46 | $create_payroll_details = $request->except('_token'); 47 | $tax_percentage = $request->get('tax_percentage'); 48 | $gross_salary = $request->get('gross_salary'); 49 | $create_payroll_details = array_add($create_payroll_details, 'net_salary', (1 - ($tax_percentage / 100)) * $gross_salary); 50 | return $create_payroll_details; 51 | } 52 | 53 | 54 | 55 | 56 | } -------------------------------------------------------------------------------- /app/Repositories/StaffProfileImageRepository.php: -------------------------------------------------------------------------------- 1 | hasFile('image')){ 19 | $filename = $request['name'] . time() . '.' . $request->image->getClientOriginalExtension(); 20 | $request->image->move(storage_path($path), $filename); 21 | return $filename; 22 | } 23 | else { 24 | return false; 25 | } 26 | } 27 | 28 | 29 | } -------------------------------------------------------------------------------- /app/Repositories/StaffRepository.php: -------------------------------------------------------------------------------- 1 | profile_image = $imageRepository; 25 | $this->admin_repository = $admin_repository; 26 | } 27 | 28 | public function createStaff(Request $request, RespondsToStaffCreated $respondsToStaffCreated){ 29 | 30 | $profile_image = $this->profile_image->saveProfileImage($request); 31 | if (!$profile_image) { 32 | return $respondsToStaffCreated->unSuccessfulResponse("No file selected!"); 33 | } 34 | 35 | $admin = $this->admin_repository->createUser($request); 36 | $staff_details = $this->buildStaffProperties($request, $profile_image, $admin); 37 | $create_staff = Staff::create($staff_details); 38 | if ($create_staff) { 39 | return $respondsToStaffCreated->successfulResponse("Staff Created Successfully"); 40 | } 41 | return $respondsToStaffCreated->unSuccessfulResponse("Unable to create Staff"); 42 | } 43 | 44 | 45 | public function getAllStaff(){ 46 | 47 | return Staff::with('user')->orderBy('created_at', 'asc')->get(); 48 | } 49 | 50 | 51 | public function getOneStaff(Staff $staff){ 52 | $staff = Staff::with('user')->whereId($staff->id)->first(); 53 | return view("staff-show", compact('staff')); 54 | } 55 | 56 | 57 | public function updateStaffProfile(Request $request, $staff_id,RespondsToStaffCreated $respondsToStaffCreated){ 58 | $staff = Staff::find($staff_id); 59 | $filename = $this->profile_image->saveProfileImage($request); 60 | 61 | if (!$filename) { 62 | $filename = $staff->image; 63 | } 64 | $admin = $this->admin_repository->updateUser($request, $request->get('user_id')); 65 | $staff_details = $this->buildStaffProperties($request, $filename, $admin); 66 | $update_staff = Staff::where('id', $staff->id)->update($staff_details); 67 | if ($update_staff) { 68 | return $respondsToStaffCreated->successfulResponse("Staff Updated Successfully"); 69 | } 70 | return $respondsToStaffCreated->unSuccessfulResponse("Unable to Update Staff"); 71 | } 72 | 73 | 74 | public function deleteStaff($staff_id){ 75 | $staff = Staff::where('id', $staff_id)->first(); 76 | $user_account = User::find($staff->user_id); 77 | $staff->delete(); 78 | $user_account->delete(); 79 | return redirect()->back()->with('message', 'Successfully removed staff member from database'); 80 | } 81 | 82 | 83 | 84 | 85 | /** 86 | * @param Request $request 87 | * @param $profile_image 88 | * @param $admin 89 | * @return array 90 | */ 91 | private function buildStaffProperties(Request $request, $profile_image, $admin) 92 | { 93 | $staff_details = $request->except("_token", "image", "name", "email","is_admin","_method"); 94 | $staff_details = array_add($staff_details, "image", $profile_image); 95 | $staff_details = array_add($staff_details, "user_id", $admin->id); 96 | return $staff_details; 97 | } 98 | 99 | 100 | } -------------------------------------------------------------------------------- /app/Repositories/UserRepository.php: -------------------------------------------------------------------------------- 1 | buildUserProperties($request); 28 | $create_admin = User::create($create_admin_details); 29 | SendAdminLoginJob::dispatch($create_admin, $password = ['password' => $generate_password]); 30 | return $create_admin; 31 | } 32 | 33 | 34 | /** 35 | * @param Request $request 36 | * @return array 37 | */ 38 | public function buildUserProperties(Request $request) 39 | { 40 | $create_admin_details = ['name' => $request->get('name'), 'email' => $request->get('email')]; 41 | $generate_password = str_random(5); 42 | $create_admin_details = array_add($create_admin_details, 'password', bcrypt($generate_password)); 43 | if ($request->get('is_admin')) { 44 | $create_admin_details = array_add($create_admin_details, 'is_admin', true); 45 | } 46 | return [$create_admin_details, $generate_password]; 47 | } 48 | 49 | 50 | /** 51 | * @param Request $request , $id 52 | * @return 53 | */ 54 | public function updateUser(Request $request, $id) 55 | { 56 | $update_details = ['name' => $request->get('name'), 'email' => $request->get('email')]; 57 | if ($request->get('is_admin')) { 58 | $update_details = array_add($update_details,'is_admin', true); 59 | } 60 | User::where('id', $id)->update($update_details); 61 | 62 | return User::where('id', $id)->first(); 63 | } 64 | 65 | 66 | } -------------------------------------------------------------------------------- /app/Staff.php: -------------------------------------------------------------------------------- 1 | belongsTo(User::class, 'user_id'); 21 | } 22 | 23 | public function getOutStandingLeaveDays($upto = null){ 24 | if (is_null($upto)) { 25 | $upto = Carbon::now(); 26 | } 27 | return ($this->getTotalAccruedLeaveDays($upto) - $this->getTotalLeaveDaysTaken()); 28 | } 29 | 30 | public function getTotalAccruedLeaveDays($upto = null){ 31 | 32 | if (is_null($upto)) { 33 | $upto = Carbon::now(); 34 | } 35 | return (env("ACCRUED_LEAVE_DAYS_IN_A_MONTH") * ($this->start_work_date->diffInMonths($upto))); 36 | } 37 | 38 | 39 | public function getTotalLeaveDaysTaken(){ 40 | 41 | return $this->getAllApproveLeaveTaken()->reduce(function ($carry, $item){ 42 | return $carry += (getNumberOfWeekDaysBetweenTwoDates($item->leave_start_date, $item->leave_end_date)); 43 | }, 0); 44 | 45 | } 46 | 47 | 48 | public function getAllApproveLeaveTaken(){ 49 | return $this->leaves()->where('is_approved', true)->get(); 50 | } 51 | 52 | public function leaves(){ 53 | 54 | return $this->hasMany(StaffLeave::class, 'staff_id'); 55 | } 56 | 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /app/StaffLeave.php: -------------------------------------------------------------------------------- 1 | 'boolean']; 17 | 18 | public function staff(){ 19 | return $this->belongsTo(Staff::class, 'staff_id'); 20 | } 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app/User.php: -------------------------------------------------------------------------------- 1 | 'boolean' 33 | ]; 34 | 35 | public function staff(){ 36 | return $this->hasOne(Staff::class, 'user_id'); 37 | } 38 | 39 | 40 | 41 | 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /app/helpers.php: -------------------------------------------------------------------------------- 1 | diffInWeekdays($to); 13 | if ($to->isWeekday()) { 14 | return $week_days + 1; 15 | } 16 | return $week_days; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /artisan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | make(Illuminate\Contracts\Console\Kernel::class); 32 | 33 | $status = $kernel->handle( 34 | $input = new Symfony\Component\Console\Input\ArgvInput, 35 | new Symfony\Component\Console\Output\ConsoleOutput 36 | ); 37 | 38 | /* 39 | |-------------------------------------------------------------------------- 40 | | Shutdown The Application 41 | |-------------------------------------------------------------------------- 42 | | 43 | | Once Artisan has finished running, we will fire off the shutdown events 44 | | so that any final work may be done by the application before we shut 45 | | down the process. This is the last thing to happen to the request. 46 | | 47 | */ 48 | 49 | $kernel->terminate($input, $status); 50 | 51 | exit($status); 52 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | singleton( 30 | Illuminate\Contracts\Http\Kernel::class, 31 | App\Http\Kernel::class 32 | ); 33 | 34 | $app->singleton( 35 | Illuminate\Contracts\Console\Kernel::class, 36 | App\Console\Kernel::class 37 | ); 38 | 39 | $app->singleton( 40 | Illuminate\Contracts\Debug\ExceptionHandler::class, 41 | App\Exceptions\Handler::class 42 | ); 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Return The Application 47 | |-------------------------------------------------------------------------- 48 | | 49 | | This script returns the application instance. The instance is given to 50 | | the calling script so we can separate the building of the instances 51 | | from the actual running of the application and sending responses. 52 | | 53 | */ 54 | 55 | return $app; 56 | -------------------------------------------------------------------------------- /bootstrap/autoload.php: -------------------------------------------------------------------------------- 1 | =5.6.4", 9 | "laravel/framework": "5.4.*", 10 | "laravel/tinker": "~1.0", 11 | "spinen/laravel-mail-assertions": "^0.3.4" 12 | }, 13 | "require-dev": { 14 | "fzaninotto/faker": "~1.4", 15 | "mockery/mockery": "0.9.*", 16 | "phpunit/phpunit": "~5.7" 17 | }, 18 | "autoload": { 19 | "classmap": [ 20 | "database" 21 | ], 22 | "psr-4": { 23 | "App\\": "app/" 24 | }, 25 | "files": [ 26 | "app/helpers.php" 27 | ] 28 | }, 29 | "autoload-dev": { 30 | "psr-4": { 31 | "Tests\\": "tests/" 32 | } 33 | }, 34 | "scripts": { 35 | "post-root-package-install": [ 36 | "php -r \"file_exists('.env') || copy('.env.example', '.env');\"" 37 | ], 38 | "post-create-project-cmd": [ 39 | "php artisan key:generate" 40 | ], 41 | "post-install-cmd": [ 42 | "Illuminate\\Foundation\\ComposerScripts::postInstall", 43 | "php artisan optimize" 44 | ], 45 | "post-update-cmd": [ 46 | "Illuminate\\Foundation\\ComposerScripts::postUpdate", 47 | "php artisan optimize" 48 | ] 49 | }, 50 | "config": { 51 | "preferred-install": "dist", 52 | "sort-packages": true, 53 | "optimize-autoloader": true 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /config/auth.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'guard' => 'web', 18 | 'passwords' => 'users', 19 | ], 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Authentication Guards 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Next, you may define every authentication guard for your application. 27 | | Of course, a great default configuration has been defined for you 28 | | here which uses session storage and the Eloquent user provider. 29 | | 30 | | All authentication drivers have a user provider. This defines how the 31 | | users are actually retrieved out of your database or other storage 32 | | mechanisms used by this application to persist your user's data. 33 | | 34 | | Supported: "session", "token" 35 | | 36 | */ 37 | 38 | 'guards' => [ 39 | 'web' => [ 40 | 'driver' => 'session', 41 | 'provider' => 'users', 42 | ], 43 | 44 | 'api' => [ 45 | 'driver' => 'token', 46 | 'provider' => 'users', 47 | ], 48 | ], 49 | 50 | /* 51 | |-------------------------------------------------------------------------- 52 | | User Providers 53 | |-------------------------------------------------------------------------- 54 | | 55 | | All authentication drivers have a user provider. This defines how the 56 | | users are actually retrieved out of your database or other storage 57 | | mechanisms used by this application to persist your user's data. 58 | | 59 | | If you have multiple user tables or models you may configure multiple 60 | | sources which represent each model / table. These sources may then 61 | | be assigned to any extra authentication guards you have defined. 62 | | 63 | | Supported: "database", "eloquent" 64 | | 65 | */ 66 | 67 | 'providers' => [ 68 | 'users' => [ 69 | 'driver' => 'eloquent', 70 | 'model' => App\User::class, 71 | ], 72 | 73 | // 'users' => [ 74 | // 'driver' => 'database', 75 | // 'table' => 'users', 76 | // ], 77 | ], 78 | 79 | /* 80 | |-------------------------------------------------------------------------- 81 | | Resetting Passwords 82 | |-------------------------------------------------------------------------- 83 | | 84 | | You may specify multiple password reset configurations if you have more 85 | | than one user table or model in the application and you want to have 86 | | separate password reset settings based on the specific user types. 87 | | 88 | | The expire time is the number of minutes that the reset token should be 89 | | considered valid. This security feature keeps tokens short-lived so 90 | | they have less time to be guessed. You may change this as needed. 91 | | 92 | */ 93 | 94 | 'passwords' => [ 95 | 'users' => [ 96 | 'provider' => 'users', 97 | 'table' => 'password_resets', 98 | 'expire' => 60, 99 | ], 100 | ], 101 | 102 | ]; 103 | -------------------------------------------------------------------------------- /config/broadcasting.php: -------------------------------------------------------------------------------- 1 | env('BROADCAST_DRIVER', 'null'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Broadcast Connections 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may define all of the broadcast connections that will be used 26 | | to broadcast events to other systems or over websockets. Samples of 27 | | each available type of connection are provided inside this array. 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'pusher' => [ 34 | 'driver' => 'pusher', 35 | 'key' => env('PUSHER_APP_KEY'), 36 | 'secret' => env('PUSHER_APP_SECRET'), 37 | 'app_id' => env('PUSHER_APP_ID'), 38 | 'options' => [ 39 | // 40 | ], 41 | ], 42 | 43 | 'redis' => [ 44 | 'driver' => 'redis', 45 | 'connection' => 'default', 46 | ], 47 | 48 | 'log' => [ 49 | 'driver' => 'log', 50 | ], 51 | 52 | 'null' => [ 53 | 'driver' => 'null', 54 | ], 55 | 56 | ], 57 | 58 | ]; 59 | -------------------------------------------------------------------------------- /config/cache.php: -------------------------------------------------------------------------------- 1 | env('CACHE_DRIVER', 'file'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Cache Stores 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may define all of the cache "stores" for your application as 26 | | well as their drivers. You may even define multiple stores for the 27 | | same cache driver to group types of items stored in your caches. 28 | | 29 | */ 30 | 31 | 'stores' => [ 32 | 33 | 'apc' => [ 34 | 'driver' => 'apc', 35 | ], 36 | 37 | 'array' => [ 38 | 'driver' => 'array', 39 | ], 40 | 41 | 'database' => [ 42 | 'driver' => 'database', 43 | 'table' => 'cache', 44 | 'connection' => null, 45 | ], 46 | 47 | 'file' => [ 48 | 'driver' => 'file', 49 | 'path' => storage_path('framework/cache/data'), 50 | ], 51 | 52 | 'memcached' => [ 53 | 'driver' => 'memcached', 54 | 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), 55 | 'sasl' => [ 56 | env('MEMCACHED_USERNAME'), 57 | env('MEMCACHED_PASSWORD'), 58 | ], 59 | 'options' => [ 60 | // Memcached::OPT_CONNECT_TIMEOUT => 2000, 61 | ], 62 | 'servers' => [ 63 | [ 64 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'), 65 | 'port' => env('MEMCACHED_PORT', 11211), 66 | 'weight' => 100, 67 | ], 68 | ], 69 | ], 70 | 71 | 'redis' => [ 72 | 'driver' => 'redis', 73 | 'connection' => 'default', 74 | ], 75 | 76 | ], 77 | 78 | /* 79 | |-------------------------------------------------------------------------- 80 | | Cache Key Prefix 81 | |-------------------------------------------------------------------------- 82 | | 83 | | When utilizing a RAM based store such as APC or Memcached, there might 84 | | be other applications utilizing the same cache. So, we'll specify a 85 | | value to get prefixed to all our keys so we can avoid collisions. 86 | | 87 | */ 88 | 89 | 'prefix' => 'laravel', 90 | 91 | ]; 92 | -------------------------------------------------------------------------------- /config/filesystems.php: -------------------------------------------------------------------------------- 1 | env('FILESYSTEM_DRIVER', 'local'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Default Cloud Filesystem Disk 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Many applications store files both locally and in the cloud. For this 24 | | reason, you may specify a default "cloud" driver here. This driver 25 | | will be bound as the Cloud disk implementation in the container. 26 | | 27 | */ 28 | 29 | 'cloud' => env('FILESYSTEM_CLOUD', 's3'), 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Filesystem Disks 34 | |-------------------------------------------------------------------------- 35 | | 36 | | Here you may configure as many filesystem "disks" as you wish, and you 37 | | may even configure multiple disks of the same driver. Defaults have 38 | | been setup for each driver as an example of the required options. 39 | | 40 | | Supported Drivers: "local", "ftp", "s3", "rackspace" 41 | | 42 | */ 43 | 44 | 'disks' => [ 45 | 46 | 'local' => [ 47 | 'driver' => 'local', 48 | 'root' => storage_path('app'), 49 | ], 50 | 51 | 'public' => [ 52 | 'driver' => 'local', 53 | 'root' => storage_path('app/public'), 54 | 'url' => env('APP_URL').'/storage', 55 | 'visibility' => 'public', 56 | ], 57 | 58 | 's3' => [ 59 | 'driver' => 's3', 60 | 'key' => env('AWS_KEY'), 61 | 'secret' => env('AWS_SECRET'), 62 | 'region' => env('AWS_REGION'), 63 | 'bucket' => env('AWS_BUCKET'), 64 | ], 65 | 66 | ], 67 | 68 | ]; 69 | -------------------------------------------------------------------------------- /config/queue.php: -------------------------------------------------------------------------------- 1 | env('QUEUE_DRIVER', 'sync'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Queue Connections 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may configure the connection information for each server that 26 | | is used by your application. A default configuration has been added 27 | | for each back-end shipped with Laravel. You are free to add more. 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'sync' => [ 34 | 'driver' => 'sync', 35 | ], 36 | 37 | 'database' => [ 38 | 'driver' => 'database', 39 | 'table' => 'jobs', 40 | 'queue' => 'default', 41 | 'retry_after' => 90, 42 | ], 43 | 44 | 'beanstalkd' => [ 45 | 'driver' => 'beanstalkd', 46 | 'host' => 'localhost', 47 | 'queue' => 'default', 48 | 'retry_after' => 90, 49 | ], 50 | 51 | 'sqs' => [ 52 | 'driver' => 'sqs', 53 | 'key' => 'your-public-key', 54 | 'secret' => 'your-secret-key', 55 | 'prefix' => 'https://sqs.us-east-1.amazonaws.com/your-account-id', 56 | 'queue' => 'your-queue-name', 57 | 'region' => 'us-east-1', 58 | ], 59 | 60 | 'redis' => [ 61 | 'driver' => 'redis', 62 | 'connection' => 'default', 63 | 'queue' => 'default', 64 | 'retry_after' => 90, 65 | ], 66 | 67 | ], 68 | 69 | /* 70 | |-------------------------------------------------------------------------- 71 | | Failed Queue Jobs 72 | |-------------------------------------------------------------------------- 73 | | 74 | | These options configure the behavior of failed queue job logging so you 75 | | can control which database and table are used to store the jobs that 76 | | have failed. You may change them to any database / table you wish. 77 | | 78 | */ 79 | 80 | 'failed' => [ 81 | 'database' => env('DB_CONNECTION', 'mysql'), 82 | 'table' => 'failed_jobs', 83 | ], 84 | 85 | ]; 86 | -------------------------------------------------------------------------------- /config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'domain' => env('MAILGUN_DOMAIN'), 19 | 'secret' => env('MAILGUN_SECRET'), 20 | ], 21 | 22 | 'ses' => [ 23 | 'key' => env('SES_KEY'), 24 | 'secret' => env('SES_SECRET'), 25 | 'region' => 'us-east-1', 26 | ], 27 | 28 | 'sparkpost' => [ 29 | 'secret' => env('SPARKPOST_SECRET'), 30 | ], 31 | 32 | 'stripe' => [ 33 | 'model' => App\User::class, 34 | 'key' => env('STRIPE_KEY'), 35 | 'secret' => env('STRIPE_SECRET'), 36 | ], 37 | 38 | ]; 39 | -------------------------------------------------------------------------------- /config/view.php: -------------------------------------------------------------------------------- 1 | [ 17 | resource_path('views'), 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled View Path 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This option determines where all the compiled Blade templates will be 26 | | stored for your application. Typically, this is within the storage 27 | | directory. However, as usual, you are free to change this value. 28 | | 29 | */ 30 | 31 | 'compiled' => realpath(storage_path('framework/views')), 32 | 33 | ]; 34 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | -------------------------------------------------------------------------------- /database/factories/ModelFactory.php: -------------------------------------------------------------------------------- 1 | define(App\User::class, function (Faker\Generator $faker) { 16 | static $password; 17 | 18 | return [ 19 | 'name' => $faker->name, 20 | 'email' => $faker->unique()->safeEmail, 21 | 'password' => $password ?: $password = bcrypt('secret'), 22 | 'remember_token' => str_random(10), 23 | ]; 24 | }); 25 | 26 | 27 | 28 | 29 | 30 | $factory->define(App\Staff::class, function (Faker\Generator $faker) { 31 | 32 | $levels = ['Intern', 'Junior', 'Senior', 'Supervisor', 'Manager']; 33 | 34 | return [ 35 | 'age' => $faker->randomNumber(), 36 | 'phone' => $faker->phoneNumber, 37 | 'image' => $faker->imageUrl(), 38 | 'address' => $faker->address, 39 | 'city' => $faker->city, 40 | 'state' => $faker->city, 41 | 'country' => $faker->country, 42 | 'level' => $levels[rand(1,4)], 43 | 'user_id' => \App\User::first()->id, 44 | 'start_work_date' => $faker->date(), 45 | ]; 46 | }); 47 | 48 | 49 | $factory->define(App\Payroll::class, function (Faker\Generator $faker) { 50 | 51 | $percentage = rand(1,10); 52 | $gross_salary = $faker->numberBetween(10000, 14500); 53 | 54 | return [ 55 | 'staff_id' => \App\Staff::all()->random()->id, 56 | 'gross_salary' => $gross_salary, 57 | 'tax_percentage' => $percentage, 58 | 'net_salary' => (1 - ($percentage / 100)) *$gross_salary, 59 | 'month' => $faker->monthName, 60 | 'year' => $faker->year(), 61 | 'comment' => $faker->sentence, 62 | ]; 63 | 64 | }); 65 | 66 | 67 | 68 | 69 | $factory->define(App\StaffLeave::class, function (Faker\Generator $faker) { 70 | return [ 71 | 'staff_id' => \App\Staff::all()->random()->id, 72 | 'reason_for_leave' => $faker->paragraph, 73 | 'leave_start_date' => $faker->dateTimeThisMonth('-1 week'), 74 | 'leave_end_date' => $faker->dateTimeThisMonth, 75 | 'is_approved' => $faker->boolean, 76 | ]; 77 | }); -------------------------------------------------------------------------------- /database/migrations/2014_10_12_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('name'); 19 | $table->string('email')->unique(); 20 | $table->string('password'); 21 | $table->boolean('is_admin')->default(false); 22 | $table->rememberToken(); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('users'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_100000_create_password_resets_table.php: -------------------------------------------------------------------------------- 1 | string('email')->index(); 18 | $table->string('token'); 19 | $table->timestamp('created_at')->nullable(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('password_resets'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /database/migrations/2017_08_28_173952_create_staff_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->integer('age'); 19 | $table->string('phone'); 20 | $table->string('image'); 21 | $table->string('address'); 22 | $table->string('city'); 23 | $table->string('state'); 24 | $table->string('country') 25 | ->default('Nigeria') 26 | ->nullable(); 27 | $table->enum('level', [ 28 | 'Intern', 29 | 'Junior', 30 | 'Senior', 31 | 'Supervisor', 32 | 'Manager' 33 | ])->default('Intern'); 34 | $table->integer('user_id'); 35 | $table->timestamps(); 36 | $table->timestamp('start_work_date')->nullable(); 37 | 38 | }); 39 | } 40 | 41 | /** 42 | * Reverse the migrations. 43 | * 44 | * @return void 45 | */ 46 | public function down() 47 | { 48 | Schema::dropIfExists('staff'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /database/migrations/2018_12_14_070056_create_audit_trails_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->integer('admin_id'); 19 | $table->longText('trail_activity_details'); 20 | $table->enum('resource_type_affected', ['staff','admin','messaging','payroll']); 21 | $table->integer('affected_resource_id'); 22 | $table->timestamps(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('audit_trails'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /database/migrations/2018_12_14_073918_create_jobs_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 18 | $table->string('queue'); 19 | $table->longText('payload'); 20 | $table->unsignedTinyInteger('attempts'); 21 | $table->unsignedInteger('reserved_at')->nullable(); 22 | $table->unsignedInteger('available_at'); 23 | $table->unsignedInteger('created_at'); 24 | 25 | $table->index(['queue', 'reserved_at']); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('jobs'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /database/migrations/2018_12_14_081558_create_messages_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->integer('sender_id'); 19 | $table->integer('recipient_id'); 20 | $table->string('subject'); 21 | $table->longText('content'); 22 | $table->boolean('is_delivered')->default(false); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('messages'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database/migrations/2018_12_19_105306_create_payrolls_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->integer('staff_id'); 19 | $table->float('gross_salary'); 20 | $table->float('tax_percentage'); 21 | $table->float('net_salary'); 22 | $table->enum('month',['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October','November', 'December']); 23 | $table->string('year'); 24 | $table->text("comment")->nullable(); 25 | $table->timestamps(); 26 | }); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('payrolls'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /database/migrations/2019_01_03_233410_create_staff_leaves_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->integer('staff_id'); 19 | $table->mediumText('reason_for_leave'); 20 | $table->timestamp('leave_start_date'); 21 | $table->timestamp('leave_end_date'); 22 | $table->boolean('is_approved')->default(false); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | /** 28 | * Reverse the migrations. 29 | * 30 | * @return void 31 | */ 32 | public function down() 33 | { 34 | Schema::dropIfExists('staff_leaves'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /database/seeds/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call(UsersTableSeeder::class); 15 | $this->call(StaffTableSeeder::class); 16 | $this->call(StaffLeaveTableSeeder::class); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /database/seeds/StaffLeaveTableSeeder.php: -------------------------------------------------------------------------------- 1 | insert([ 16 | 'staff_id' => \App\Staff::find(rand(1,2))->id, 17 | 'reason_for_leave' => 'I just want leave, just give me.', 18 | 'leave_start_date' => \Carbon\Carbon::now()->addWeek(), 19 | 'leave_end_date' => \Carbon\Carbon::now()->addWeeks(2), 20 | 'is_approved' => true, 21 | ]); 22 | 23 | DB::table('staff_leaves')->insert([ 24 | 'staff_id' => \App\Staff::find(rand(1,2))->id, 25 | 'reason_for_leave' => 'I just want to go for leave', 26 | 'leave_start_date' => \Carbon\Carbon::now()->addWeeks(2), 27 | 'leave_end_date' => \Carbon\Carbon::now()->addWeeks(2), 28 | 'is_approved' => true, 29 | ]); 30 | 31 | DB::table('staff_leaves')->insert([ 32 | 'staff_id' => \App\Staff::find(rand(1,2))->id, 33 | 'reason_for_leave' => 'I just want leave, just give me.', 34 | 'leave_start_date' => \Carbon\Carbon::now()->addWeeks(3), 35 | 'leave_end_date' => \Carbon\Carbon::now()->addWeeks(4), 36 | 'is_approved' => true, 37 | ]); 38 | 39 | DB::table('staff_leaves')->insert([ 40 | 'staff_id' => \App\Staff::find(rand(1,2))->id, 41 | 'reason_for_leave' => 'I just want to go for leave', 42 | 'leave_start_date' => \Carbon\Carbon::now()->addWeeks(4), 43 | 'leave_end_date' => \Carbon\Carbon::now()->addWeeks(5), 44 | 'is_approved' => false, 45 | ]); 46 | 47 | DB::table('staff_leaves')->insert([ 48 | 'staff_id' => \App\Staff::find(rand(1,2))->id, 49 | 'reason_for_leave' => 'I just want leave, just give me.', 50 | 'leave_start_date' => \Carbon\Carbon::now()->addWeeks(5), 51 | 'leave_end_date' => \Carbon\Carbon::now()->addWeeks(6), 52 | 'is_approved' => true, 53 | ]); 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /database/seeds/StaffTableSeeder.php: -------------------------------------------------------------------------------- 1 | insert([ 16 | 'age' => 29, 17 | 'phone' => +233204040404, 18 | 'image' => 'Eshan Faiq Aliu1546381064.jpg', 19 | 'address' => 'Shallom Estate, Accra', 20 | 'city' => 'Accra', 21 | 'state' => 'Greater Accra', 22 | 'country' => 'Ghana', 23 | 'level' => 'Manager', 24 | 'user_id' => \App\User::first()->id, 25 | 'created_at' => \Carbon\Carbon::now()->subMonths(20), 26 | 'updated_at' => \Carbon\Carbon::now()->subMonths(3), 27 | 'start_work_date' => \Carbon\Carbon::now()->subMonths(19), 28 | ]); 29 | 30 | 31 | 32 | DB::table('staff')->insert([ 33 | 'age' => 29, 34 | 'phone' => +2332040422, 35 | 'image' => 'Eshan Faiq Aliu1546381064.jpg', 36 | 'address' => 'Shallom Estate, Accra', 37 | 'city' => 'Accra', 38 | 'state' => 'Greater Accra', 39 | 'country' => 'Ghana', 40 | 'level' => 'Manager', 41 | 'user_id' => \App\User::find(2)->id, 42 | 'created_at' => \Carbon\Carbon::now()->subMonths(20), 43 | 'updated_at' => \Carbon\Carbon::now()->subMonths(3), 44 | 'start_work_date' => \Carbon\Carbon::now()->subMonths(19), 45 | ]); 46 | 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /database/seeds/UsersTableSeeder.php: -------------------------------------------------------------------------------- 1 | insert([ 15 | 'name' => 'Gbeila Aliu Wahab', 16 | 'email' => 'aliuwahab@gmail.com', 17 | 'password' => bcrypt('secret'), 18 | 'is_admin' => true, 19 | 'created_at' => \Carbon\Carbon::now(), 20 | 'updated_at' => \Carbon\Carbon::now(), 21 | ]); 22 | 23 | 24 | DB::table('users')->insert([ 25 | 'name' => 'Faiq Eshan Aliu', 26 | 'email' => 'admin@site.com', 27 | 'password' => bcrypt('secret'), 28 | 'is_admin' => false, 29 | 'created_at' => \Carbon\Carbon::now(), 30 | 'updated_at' => \Carbon\Carbon::now(), 31 | ]); 32 | 33 | 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "npm run development", 5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 6 | "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 7 | "watch-poll": "npm run watch -- --watch-poll", 8 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", 9 | "prod": "npm run production", 10 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" 11 | }, 12 | "devDependencies": { 13 | "axios": "^0.19.0", 14 | "bootstrap-sass": "^3.3.7", 15 | "cross-env": "^5.0.1", 16 | "jquery": "^3.1.1", 17 | "laravel-mix": "^1.0", 18 | "lodash": "^4.17.4", 19 | "vue": "^2.1.10" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests/Feature 14 | 15 | 16 | 17 | ./tests/Unit 18 | 19 | 20 | 21 | 22 | ./app 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Redirect Trailing Slashes If Not A Folder... 9 | RewriteCond %{REQUEST_FILENAME} !-d 10 | RewriteRule ^(.*)/$ /$1 [L,R=301] 11 | 12 | # Handle Front Controller... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_FILENAME} !-f 15 | RewriteRule ^ index.php [L] 16 | 17 | # Handle Authorization Header 18 | RewriteCond %{HTTP:Authorization} . 19 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 20 | 21 | -------------------------------------------------------------------------------- /public/css/staff-profile.css: -------------------------------------------------------------------------------- 1 | .user-row { 2 | margin-bottom: 14px; 3 | } 4 | 5 | .user-row:last-child { 6 | margin-bottom: 0; 7 | } 8 | 9 | .dropdown-user { 10 | margin: 13px 0; 11 | padding: 5px; 12 | height: 100%; 13 | } 14 | 15 | .dropdown-user:hover { 16 | cursor: pointer; 17 | } 18 | 19 | .table-user-information > tbody > tr { 20 | border-top: 1px solid rgb(221, 221, 221); 21 | } 22 | 23 | .table-user-information > tbody > tr:first-child { 24 | border-top: 0; 25 | } 26 | 27 | 28 | .table-user-information > tbody > tr > td { 29 | border-top: 0; 30 | } 31 | .toppad 32 | {margin-top:20px; 33 | } 34 | -------------------------------------------------------------------------------- /public/css/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | height: 100%; 3 | padding-top: 80px; 4 | padding-bottom: 80px; 5 | } 6 | 7 | .siteFooter { 8 | position: fixed; 9 | display: block; 10 | width: 100%; 11 | padding: 10px; 12 | height: 50px; 13 | bottom: 0; 14 | color: #FFF; 15 | } -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwebwiz/staff-management-system/01feed1dc0bb80d6032700a50ddefd25e603fd76/public/favicon.ico -------------------------------------------------------------------------------- /public/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwebwiz/staff-management-system/01feed1dc0bb80d6032700a50ddefd25e603fd76/public/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /public/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwebwiz/staff-management-system/01feed1dc0bb80d6032700a50ddefd25e603fd76/public/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /public/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwebwiz/staff-management-system/01feed1dc0bb80d6032700a50ddefd25e603fd76/public/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /public/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwebwiz/staff-management-system/01feed1dc0bb80d6032700a50ddefd25e603fd76/public/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /public/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwebwiz/staff-management-system/01feed1dc0bb80d6032700a50ddefd25e603fd76/public/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwebwiz/staff-management-system/01feed1dc0bb80d6032700a50ddefd25e603fd76/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwebwiz/staff-management-system/01feed1dc0bb80d6032700a50ddefd25e603fd76/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwebwiz/staff-management-system/01feed1dc0bb80d6032700a50ddefd25e603fd76/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamwebwiz/staff-management-system/01feed1dc0bb80d6032700a50ddefd25e603fd76/public/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | 10 | /* 11 | |-------------------------------------------------------------------------- 12 | | Register The Auto Loader 13 | |-------------------------------------------------------------------------- 14 | | 15 | | Composer provides a convenient, automatically generated class loader for 16 | | our application. We just need to utilize it! We'll simply require it 17 | | into the script here so that we don't have to worry about manual 18 | | loading any of our classes later on. It feels great to relax. 19 | | 20 | */ 21 | 22 | require __DIR__.'/../bootstrap/autoload.php'; 23 | 24 | /* 25 | |-------------------------------------------------------------------------- 26 | | Turn On The Lights 27 | |-------------------------------------------------------------------------- 28 | | 29 | | We need to illuminate PHP development, so let us turn on the lights. 30 | | This bootstraps the framework and gets it ready for use, then it 31 | | will load up this application so that we can run it and send 32 | | the responses back to the browser and delight our users. 33 | | 34 | */ 35 | 36 | $app = require_once __DIR__.'/../bootstrap/app.php'; 37 | 38 | /* 39 | |-------------------------------------------------------------------------- 40 | | Run The Application 41 | |-------------------------------------------------------------------------- 42 | | 43 | | Once we have the application, we can handle the incoming request 44 | | through the kernel, and send the associated response back to 45 | | the client's browser allowing them to enjoy the creative 46 | | and wonderful application we have prepared for them. 47 | | 48 | */ 49 | 50 | $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); 51 | 52 | $response = $kernel->handle( 53 | $request = Illuminate\Http\Request::capture() 54 | ); 55 | 56 | $response->send(); 57 | 58 | $kernel->terminate($request, $response); 59 | -------------------------------------------------------------------------------- /public/less/animated.less: -------------------------------------------------------------------------------- 1 | // Animated Icons 2 | // -------------------------- 3 | 4 | .@{fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .@{fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /public/less/bordered-pulled.less: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em @fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .@{fa-css-prefix}-pull-left { float: left; } 11 | .@{fa-css-prefix}-pull-right { float: right; } 12 | 13 | .@{fa-css-prefix} { 14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .@{fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /public/less/core.less: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /public/less/fixed-width.less: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .@{fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /public/less/font-awesome.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables.less"; 7 | @import "mixins.less"; 8 | @import "path.less"; 9 | @import "core.less"; 10 | @import "larger.less"; 11 | @import "fixed-width.less"; 12 | @import "list.less"; 13 | @import "bordered-pulled.less"; 14 | @import "animated.less"; 15 | @import "rotated-flipped.less"; 16 | @import "stacked.less"; 17 | @import "icons.less"; 18 | @import "screen-reader.less"; 19 | -------------------------------------------------------------------------------- /public/less/larger.less: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .@{fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .@{fa-css-prefix}-2x { font-size: 2em; } 11 | .@{fa-css-prefix}-3x { font-size: 3em; } 12 | .@{fa-css-prefix}-4x { font-size: 4em; } 13 | .@{fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /public/less/list.less: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: @fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .@{fa-css-prefix}-li { 11 | position: absolute; 12 | left: -@fa-li-width; 13 | width: @fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.@{fa-css-prefix}-lg { 17 | left: (-@fa-li-width + (4em / 14)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /public/less/mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | .fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | .fa-icon-rotate(@degrees, @rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})"; 16 | -webkit-transform: rotate(@degrees); 17 | -ms-transform: rotate(@degrees); 18 | transform: rotate(@degrees); 19 | } 20 | 21 | .fa-icon-flip(@horiz, @vert, @rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)"; 23 | -webkit-transform: scale(@horiz, @vert); 24 | -ms-transform: scale(@horiz, @vert); 25 | transform: scale(@horiz, @vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | .sr-only() { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | .sr-only-focusable() { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /public/less/path.less: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); 7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), 8 | url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'), 9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), 10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), 11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /public/less/rotated-flipped.less: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } 5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } 6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } 7 | 8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } 9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .@{fa-css-prefix}-rotate-90, 15 | :root .@{fa-css-prefix}-rotate-180, 16 | :root .@{fa-css-prefix}-rotate-270, 17 | :root .@{fa-css-prefix}-flip-horizontal, 18 | :root .@{fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /public/less/screen-reader.less: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { .sr-only(); } 5 | .sr-only-focusable { .sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /public/less/stacked.less: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; } 21 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /public/scss/_animated.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .#{$fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /public/scss/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .#{$fa-css-prefix}-pull-left { float: left; } 11 | .#{$fa-css-prefix}-pull-right { float: right; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .#{$fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /public/scss/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /public/scss/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /public/scss/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /public/scss/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /public/scss/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------- 3 | 4 | @mixin fa-icon() { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | 14 | @mixin fa-icon-rotate($degrees, $rotation) { 15 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})"; 16 | -webkit-transform: rotate($degrees); 17 | -ms-transform: rotate($degrees); 18 | transform: rotate($degrees); 19 | } 20 | 21 | @mixin fa-icon-flip($horiz, $vert, $rotation) { 22 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)"; 23 | -webkit-transform: scale($horiz, $vert); 24 | -ms-transform: scale($horiz, $vert); 25 | transform: scale($horiz, $vert); 26 | } 27 | 28 | 29 | // Only display content to screen readers. A la Bootstrap 4. 30 | // 31 | // See: http://a11yproject.com/posts/how-to-hide-content/ 32 | 33 | @mixin sr-only { 34 | position: absolute; 35 | width: 1px; 36 | height: 1px; 37 | padding: 0; 38 | margin: -1px; 39 | overflow: hidden; 40 | clip: rect(0,0,0,0); 41 | border: 0; 42 | } 43 | 44 | // Use in conjunction with .sr-only to only display content when it's focused. 45 | // 46 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 47 | // 48 | // Credit: HTML5 Boilerplate 49 | 50 | @mixin sr-only-focusable { 51 | &:active, 52 | &:focus { 53 | position: static; 54 | width: auto; 55 | height: auto; 56 | margin: 0; 57 | overflow: visible; 58 | clip: auto; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /public/scss/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); 7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), 9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), 10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /public/scss/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .#{$fa-css-prefix}-rotate-90, 15 | :root .#{$fa-css-prefix}-rotate-180, 16 | :root .#{$fa-css-prefix}-rotate-270, 17 | :root .#{$fa-css-prefix}-flip-horizontal, 18 | :root .#{$fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /public/scss/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { @include sr-only(); } 5 | .sr-only-focusable { @include sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /public/scss/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /public/scss/font-awesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | @import "larger"; 11 | @import "fixed-width"; 12 | @import "list"; 13 | @import "bordered-pulled"; 14 | @import "animated"; 15 | @import "rotated-flipped"; 16 | @import "stacked"; 17 | @import "icons"; 18 | @import "screen-reader"; 19 | -------------------------------------------------------------------------------- /public/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Staff Management System 2 | 3 | This little buddy can help you manage your staff database! Built with :sparkling_heart: with Laravel 4 | 5 | #FEATURES 6 | 7 | - 1 Staff management/ database 8 | - 2. Staff Leave Management 9 | - 3. Staff Payslip Generation/Emailing 10 | - 4. Messaging of Staff 11 | - ETC. 12 | 13 | ## MAKE Sure to look at the .env.example to see the list of simple configuration options to achieve more. 14 | 15 | 16 | 17 | ### After configuration, 18 | #### RUN: php artisan migrate 19 | #### RUN: php artisan db:seed 20 | 21 | ##### Example Admin/Staff users : Check the seed files 22 | 23 | 24 | -------------------------------------------------------------------------------- /resources/assets/js/app.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * First we will load all of this project's JavaScript dependencies which 4 | * includes Vue and other libraries. It is a great starting point when 5 | * building robust, powerful web applications using Vue and Laravel. 6 | */ 7 | 8 | require('./bootstrap'); 9 | 10 | window.Vue = require('vue'); 11 | 12 | /** 13 | * Next, we will create a fresh Vue application instance and attach it to 14 | * the page. Then, you may begin adding components to this application 15 | * or customize the JavaScript scaffolding to fit your unique needs. 16 | */ 17 | 18 | Vue.component('example', require('./components/Example.vue')); 19 | 20 | const app = new Vue({ 21 | el: '#app' 22 | }); 23 | -------------------------------------------------------------------------------- /resources/assets/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | 2 | window._ = require('lodash'); 3 | 4 | /** 5 | * We'll load jQuery and the Bootstrap jQuery plugin which provides support 6 | * for JavaScript based Bootstrap features such as modals and tabs. This 7 | * code may be modified to fit the specific needs of your application. 8 | */ 9 | 10 | try { 11 | window.$ = window.jQuery = require('jquery'); 12 | 13 | require('bootstrap-sass'); 14 | } catch (e) {} 15 | 16 | /** 17 | * We'll load the axios HTTP library which allows us to easily issue requests 18 | * to our Laravel back-end. This library automatically handles sending the 19 | * CSRF token as a header based on the value of the "XSRF" token cookie. 20 | */ 21 | 22 | window.axios = require('axios'); 23 | 24 | window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 25 | 26 | /** 27 | * Next we will register the CSRF Token as a common header with Axios so that 28 | * all outgoing HTTP requests automatically have it attached. This is just 29 | * a simple convenience so we don't have to attach every token manually. 30 | */ 31 | 32 | let token = document.head.querySelector('meta[name="csrf-token"]'); 33 | 34 | if (token) { 35 | window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content; 36 | } else { 37 | console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token'); 38 | } 39 | 40 | /** 41 | * Echo exposes an expressive API for subscribing to channels and listening 42 | * for events that are broadcast by Laravel. Echo and event broadcasting 43 | * allows your team to easily build robust real-time web applications. 44 | */ 45 | 46 | // import Echo from 'laravel-echo' 47 | 48 | // window.Pusher = require('pusher-js'); 49 | 50 | // window.Echo = new Echo({ 51 | // broadcaster: 'pusher', 52 | // key: 'your-pusher-key' 53 | // }); 54 | -------------------------------------------------------------------------------- /resources/assets/js/components/Example.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 24 | -------------------------------------------------------------------------------- /resources/assets/sass/_variables.scss: -------------------------------------------------------------------------------- 1 | 2 | // Body 3 | $body-bg: #f5f8fa; 4 | 5 | // Borders 6 | $laravel-border-color: darken($body-bg, 10%); 7 | $list-group-border: $laravel-border-color; 8 | $navbar-default-border: $laravel-border-color; 9 | $panel-default-border: $laravel-border-color; 10 | $panel-inner-border: $laravel-border-color; 11 | 12 | // Brands 13 | $brand-primary: #3097D1; 14 | $brand-info: #8eb4cb; 15 | $brand-success: #2ab27b; 16 | $brand-warning: #cbb956; 17 | $brand-danger: #bf5329; 18 | 19 | // Typography 20 | $icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/"; 21 | $font-family-sans-serif: "Raleway", sans-serif; 22 | $font-size-base: 14px; 23 | $line-height-base: 1.6; 24 | $text-color: #636b6f; 25 | 26 | // Navbar 27 | $navbar-default-bg: #fff; 28 | 29 | // Buttons 30 | $btn-default-color: $text-color; 31 | 32 | // Inputs 33 | $input-border: lighten($text-color, 40%); 34 | $input-border-focus: lighten($brand-primary, 25%); 35 | $input-color-placeholder: lighten($text-color, 30%); 36 | 37 | // Panels 38 | $panel-default-heading-bg: #fff; 39 | -------------------------------------------------------------------------------- /resources/assets/sass/app.scss: -------------------------------------------------------------------------------- 1 | 2 | // Fonts 3 | @import url("https://fonts.googleapis.com/css?family=Raleway:300,400,600"); 4 | 5 | // Variables 6 | @import "variables"; 7 | 8 | // Bootstrap 9 | @import "node_modules/bootstrap-sass/assets/stylesheets/bootstrap"; 10 | -------------------------------------------------------------------------------- /resources/lang/en/auth.php: -------------------------------------------------------------------------------- 1 | 'These credentials do not match our records.', 17 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/lang/en/pagination.php: -------------------------------------------------------------------------------- 1 | '« Previous', 17 | 'next' => 'Next »', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/lang/en/passwords.php: -------------------------------------------------------------------------------- 1 | 'Passwords must be at least six characters and match the confirmation.', 17 | 'reset' => 'Your password has been reset!', 18 | 'sent' => 'We have e-mailed your password reset link!', 19 | 'token' => 'This password reset token is invalid.', 20 | 'user' => "We can't find a user with that e-mail address.", 21 | 22 | ]; 23 | -------------------------------------------------------------------------------- /resources/views/admin-home.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @extends('layouts.admin') 3 | 4 | @section('content') 5 | 6 | @section('body') 7 |
8 |
9 |

Welcome, {{ Auth::user()->name }}

10 |
11 | @include('parts.action-buttons') 12 |
13 |

14 |

Recent Activity

15 | 16 | 21 |

22 |
23 |
24 | @endsection 25 | 26 | @endsection 27 | -------------------------------------------------------------------------------- /resources/views/all-admin-members.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @extends('layouts.admin') 3 | 4 | @section('content') 5 | 6 | @section('body') 7 | 8 |
9 |
10 |

View all Admins

11 |
12 | 13 | @include('parts.action-buttons') 14 | 15 |
16 | @include('parts.message-block') 17 |
18 | @if (count($admins) !== 0) 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | @foreach($admins as $admin) 28 | 29 | 30 | 31 | 32 | 33 | 36 | 37 | 38 | 39 | @endforeach 40 |
S/NNameEmailAction
{{ $counter }}{{ $admin->name }}{{ $admin->email }} 34 | Edit 35 |
41 | @else 42 |

There are no admin yet!

43 | @endif 44 |
45 |
46 |
47 | 48 | @endsection 49 | 50 | @endsection -------------------------------------------------------------------------------- /resources/views/all-staff-members.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @extends('layouts.admin') 3 | 4 | @section('content') 5 | 6 | @section('body') 7 | 8 |
9 |
10 |

View all staff members

11 |
12 | 13 | @include('parts.action-buttons') 14 | 15 |
16 | @include('parts.message-block') 17 |
18 | @if (count($staff) !== 0) 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | @foreach($staff as $staff) 28 | 29 | 30 | 31 | 32 | {{----}} 33 | 34 | {{----}} 35 | 43 | 44 | 45 | 46 | @endforeach 47 |
S/NNameLevelAction
{{ $counter }}{{ $staff->user->name }}{{ $staff->email }}{{ $staff->level }}{{ $staff->phone }} 36 | View 37 | Edit 38 | Delete 39 | Message 40 | Generate Payslip 41 | 42 |
48 | @else 49 |

There are no staff yet!

50 | @endif 51 |
52 |
53 |
54 | 55 | @endsection 56 | 57 | @endsection -------------------------------------------------------------------------------- /resources/views/all-staff-payrolls.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @extends('layouts.admin') 3 | 4 | @section('content') 5 | 6 | @section('body') 7 | 8 |
9 |
10 |

View all staff members Payslips

11 |
12 | @include('parts.action-buttons') 13 |
14 | @include('parts.message-block') 15 |
16 | @if (count($payrolls) !== 0) 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | @foreach($payrolls as $payroll) 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 38 | 39 | 40 | 41 | @endforeach 42 |
S/NNameLevelGross SalaryNet SalaryAction
{{ $counter }}{{ $payroll->staff->user->name }}{{ $payroll->staff->level }}{{ $payroll->gross_salary }}{{ $payroll->net_salary }} 36 | Send Payroll to Staff 37 |
43 | @else 44 |

There are no staff payslips generated yet!

45 | @endif 46 |
47 |
48 |
49 | 50 | @endsection 51 | 52 | @endsection -------------------------------------------------------------------------------- /resources/views/apply-leave.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @extends('layouts.admin') 3 | 4 | @section('content') 5 | 6 | @section('body') 7 | 8 |
9 |
10 |

Hello You're Applying for Leave

11 |
12 | @include('parts.action-buttons') 13 |
14 | @include('parts.message-block') 15 |
16 | {{ csrf_field() }} 17 | 18 | 19 | 20 |
21 | 22 | 23 |
24 | 25 |
26 | 27 | 28 |
29 | 30 |
31 | 32 |
33 | 34 | 41 | 42 |     43 |
44 |
45 | 46 | 47 |
48 | 49 |
50 |
51 |
52 |
53 | 54 | @endsection 55 | 56 | @endsection -------------------------------------------------------------------------------- /resources/views/auth/login.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
Login
9 | 10 |
11 |
12 | {{ csrf_field() }} 13 | 14 |
15 | 16 | 17 |
18 | 19 | 20 | @if ($errors->has('email')) 21 | 22 | {{ $errors->first('email') }} 23 | 24 | @endif 25 |
26 |
27 | 28 |
29 | 30 | 31 |
32 | 33 | 34 | @if ($errors->has('password')) 35 | 36 | {{ $errors->first('password') }} 37 | 38 | @endif 39 |
40 |
41 | 42 |
43 |
44 |
45 | 48 |
49 |
50 |
51 | 52 |
53 |
54 | 57 | 58 | 59 | Forgot Your Password? 60 | 61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | @endsection 70 | -------------------------------------------------------------------------------- /resources/views/auth/passwords/email.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
Reset Password
9 | 10 |
11 | @if (session('status')) 12 |
13 | {{ session('status') }} 14 |
15 | @endif 16 | 17 |
18 | {{ csrf_field() }} 19 | 20 |
21 | 22 | 23 |
24 | 25 | 26 | @if ($errors->has('email')) 27 | 28 | {{ $errors->first('email') }} 29 | 30 | @endif 31 |
32 |
33 | 34 |
35 |
36 | 39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | @endsection 48 | -------------------------------------------------------------------------------- /resources/views/auth/passwords/reset.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
Reset Password
9 | 10 |
11 |
12 | {{ csrf_field() }} 13 | 14 | 15 | 16 |
17 | 18 | 19 |
20 | 21 | 22 | @if ($errors->has('email')) 23 | 24 | {{ $errors->first('email') }} 25 | 26 | @endif 27 |
28 |
29 | 30 |
31 | 32 | 33 |
34 | 35 | 36 | @if ($errors->has('password')) 37 | 38 | {{ $errors->first('password') }} 39 | 40 | @endif 41 |
42 |
43 | 44 |
45 | 46 |
47 | 48 | 49 | @if ($errors->has('password_confirmation')) 50 | 51 | {{ $errors->first('password_confirmation') }} 52 | 53 | @endif 54 |
55 |
56 | 57 |
58 |
59 | 62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | @endsection 71 | -------------------------------------------------------------------------------- /resources/views/auth/register.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
Register
9 | 10 |
11 |
12 | {{ csrf_field() }} 13 | 14 |
15 | 16 | 17 |
18 | 19 | 20 | @if ($errors->has('name')) 21 | 22 | {{ $errors->first('name') }} 23 | 24 | @endif 25 |
26 |
27 | 28 |
29 | 30 | 31 |
32 | 33 | 34 | @if ($errors->has('email')) 35 | 36 | {{ $errors->first('email') }} 37 | 38 | @endif 39 |
40 |
41 | 42 |
43 | 44 | 45 |
46 | 47 | 48 | @if ($errors->has('password')) 49 | 50 | {{ $errors->first('password') }} 51 | 52 | @endif 53 |
54 |
55 | 56 |
57 | 58 | 59 |
60 | 61 |
62 |
63 | 64 |
65 |
66 | 69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | @endsection 78 | -------------------------------------------------------------------------------- /resources/views/create-payslip.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @extends('layouts.admin') 3 | 4 | @section('content') 5 | 6 | @section('body') 7 | 8 |
9 |
10 |

Generate Payroll for {{ $staff->name }}

11 |
12 | Dashboard 13 | View staff members 14 |
15 | @include('parts.message-block') 16 |
17 | {{ csrf_field() }} 18 | 19 | 20 |
21 | 22 | 23 |
24 | 25 |
26 | 27 | 28 |
29 | 30 |
31 | 32 | 48 |
49 | 50 | 51 |
52 | 53 | 69 |
70 | 71 |
72 | 73 | 78 |
79 | 80 |
81 | 82 |
83 |
84 |
85 |
86 | 87 | @endsection 88 | 89 | @endsection -------------------------------------------------------------------------------- /resources/views/edit-staff-member.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @extends('layouts.admin') 3 | 4 | @section('content') 5 | @section('body') 6 | 7 |
8 |
9 |

Edit {{ $staff->user->name }}’s Profile

10 |
11 | 12 | @include('parts.action-buttons') 13 | 14 |
15 | @include('parts.message-block') 16 | 17 | {{ $staff->name }} 18 |
19 |
20 | {{ csrf_field() }} 21 | 22 | {{ method_field('PUT') }} 23 | 24 |
25 | 26 | 27 |
28 | 29 |
30 | 31 | 32 |
33 | 34 |
35 | 36 | 37 |
38 | 39 |
40 | 41 | 42 |
43 | 44 |
45 | 46 | 47 |
48 | 49 |
50 | 51 | 52 |
53 | 54 |
55 | 56 | 57 |
58 | 59 |
60 | 61 | 62 |
63 | 64 |
65 | 66 | 67 |
68 | 69 |
70 | 71 | 79 |
80 | 81 | 82 |
83 |
84 | 87 |
88 |
89 | 90 |
91 | 92 | 93 |
94 | 95 |
96 | 97 |
98 |
99 |
100 |
101 | 102 | @endsection 103 | @endsection -------------------------------------------------------------------------------- /resources/views/emails/admin-login.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 49 | 50 |
19 |
20 | 21 | 22 |
23 | 24 | 25 |

Hello {{ $admin->name }}

26 | 27 | See Your login Details Below:
28 | 29 | 30 | {{ 'Email: '.$admin->email }}
31 | 32 | {{ 'Password: '.$password['password'] }}
33 | 34 | 35 |
36 | {{----}} 37 |
38 | 39 |

40 | 41 | LOGIN URL 42 |

43 |

44 | 45 |
46 | 47 |
48 |
51 | 52 | -------------------------------------------------------------------------------- /resources/views/emails/message.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 43 | 44 |
19 |
20 | 21 | 22 |
23 | 24 | 25 |

Hello {{ $staff->user->name }}

26 | 27 | {{ $content->content }} 28 | 29 |
30 | {{----}} 31 |
32 | 33 |

34 | 35 | Get In Touch 36 |

37 |

38 | 39 |
40 | 41 |
42 |
45 | 46 | -------------------------------------------------------------------------------- /resources/views/layouts/admin.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 | 7 | @if (Auth::user()->is_admin == true) 8 | 9 | Dashboard 10 | 11 | Add New Staff 12 | View Staff Members 14 | View Payrolls 16 | View All Admins 18 | 19 |
20 | Current Pending Leave 22 | Approved Leave 24 | @endif 25 | 26 |
27 | 28 | Your Leave Situation 30 | 31 |
32 |
33 |
34 | @yield('body') 35 |
36 |
37 |
-------------------------------------------------------------------------------- /resources/views/leaves.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @extends('layouts.admin') 3 | 4 | @section('content') 5 | 6 | @section('body') 7 | 8 |
9 |
10 | {{--

View all Leaves By {{ $leaves->user->name }}

--}} 11 |

You're viewing {{ $leave_type }}

12 |
13 | 14 | @include('parts.action-buttons') 15 | 16 |
17 | @include('parts.message-block') 18 |
19 | @if (count($leaves) !== 0) 20 | {{ $counter = 1 }} 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | @foreach($leaves as $leaf) 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 50 | 51 | 52 | {{ $counter++ }} 53 | @endforeach 54 |
S/NStaff NameLeave Start DateLeave End DateReason for LeaveAction/Status
{{ $counter }}{{ $leaf->staff->user->name }}{{ $leaf->leave_start_date->format('l jS \\of F Y') }}{{ $leaf->leave_end_date->format('l jS \\of F Y') }}{{ $leaf->reason_for_leave }} 39 | @if ($leaf->is_approved == false) 40 |
41 | {{ csrf_field() }} 42 | 43 | 44 |
45 | @else 46 | Approved 47 | @endif 48 | 49 |
55 | @else 56 |

There are no {{ strtoupper($leave_type) }} yet!

57 | @endif 58 |
59 |
60 |
61 | 62 | @endsection 63 | 64 | @endsection -------------------------------------------------------------------------------- /resources/views/message.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @extends('layouts.admin') 3 | 4 | @section('content') 5 | 6 | @section('body') 7 |
8 |
9 |

Welcome, {{ Auth::user()->name }} {{ "you're about sending a message to ".$staff->user->name }}

10 |
11 | Add new staff 12 | View staff members 13 |
14 |

15 | {{--

70 |
71 | @endsection 72 | 73 | @endsection 74 | -------------------------------------------------------------------------------- /resources/views/new-staff.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @extends('layouts.admin') 3 | 4 | @section('content') 5 | 6 | @section('body') 7 | 8 |
9 |
10 |

Add New Admin/Staff

11 |
12 | @include('parts.action-buttons') 13 |
14 | @include('parts.message-block') 15 |
16 | {{ csrf_field() }} 17 |
18 | 19 | 20 |
21 | 22 |
23 | 24 | 25 |
26 | 27 |
28 | 29 | 30 |
31 | 32 |
33 | 34 | 35 |
36 | 37 |
38 | 39 | 40 |
41 | 42 |
43 | 44 | 45 |
46 | 47 |
48 | 49 | 50 |
51 | 52 |
53 | 54 | 55 |
56 | 57 |
58 | 59 | 60 |
61 | 62 |
63 | 64 | 72 |
73 | 74 |
75 |
76 | 79 |
80 |
81 | 82 |
83 | 84 | 85 |
86 | 87 |
88 | 89 |
90 |
91 |
92 |
93 | 94 | @endsection 95 | 96 | @endsection -------------------------------------------------------------------------------- /resources/views/parts/action-buttons.blade.php: -------------------------------------------------------------------------------- 1 | @if (Auth::user()->is_admin == true) 2 | 3 | {{-- Dashboard--}} 4 | View Staff Members 5 | Add New Staff/Admin 6 | All Admins 7 | View Payrolls 8 | 9 | @endif 10 | 11 | Apply for Leave 12 | -------------------------------------------------------------------------------- /resources/views/parts/message-block.blade.php: -------------------------------------------------------------------------------- 1 | @if(count($errors) > 0) 2 | @foreach($errors->all() as $error) 3 |
4 | × 5 | {{ $error }} 6 |
7 | @endforeach 8 | @endif 9 | 10 | @if(Session::has('message')) 11 |
12 | × 13 | {{ Session::get('message') }} 14 |
15 | @endif 16 | 17 | @if (Session::has('err')) 18 |
19 | × 20 | {{ Session::get('message') }} 21 |
22 | @endif -------------------------------------------------------------------------------- /resources/views/staff-show.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @extends('layouts.admin') 3 | 4 | @section('content') 5 | @section('body') 6 | 7 |
8 |
9 |

Showing {{ $staff->name }}’s Profile

10 |
11 | Dashboard 12 | Add new 13 | staff 14 | View 15 | staff members 16 |
17 | @include('parts.message-block') 18 |
19 | 20 | 21 |
22 |
23 | {{ $staff->name }} 25 |
26 | 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
Name:{{ $staff->user->name }}
Email{{ $staff->user->email }}
Age:{{ $staff->age }}
Phone Number:{{ $staff->phone }}
Address:{{ $staff->address }}
City:{{ $staff->city }}
State:{{ $staff->state }}
Country:{{ $staff->country }}
Level:{{ $staff->level }}
74 | 75 | PaySlips 76 | Leave Status 77 |
78 |
79 | 80 | 92 | 93 |
94 | 95 | 96 | 97 | 98 | @endsection 99 | @endsection -------------------------------------------------------------------------------- /resources/views/user-leaves.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @extends('layouts.admin') 3 | 4 | @section('content') 5 | 6 | @section('body') 7 | 8 |
9 |
10 |

View all Leaves By {{ $leaves->user->name }}

11 |

Your current outstanding leave days is: {{ $leaves->getOutStandingLeaveDays() }} days

12 |
13 | 14 | @include('parts.action-buttons') 15 | 16 |
17 | @include('parts.message-block') 18 |
19 | @if (count($leaves->leaves) !== 0) 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | @foreach($leaves->leaves as $leaf) 30 | 31 | 32 | 33 | 34 | 35 | 36 | 43 | 44 | 45 | 46 | @endforeach 47 |
S/NLeave Start DateLeave End DateReason for LeaveStatus
{{ $counter }}{{ $leaf->leave_start_date->format('l jS \\of F Y')}}{{ $leaf->leave_end_date->format('l jS \\of F Y')}}{{ $leaf->reason_for_leave }} 37 | @if ($leaf->is_approved == true) 38 | {{ 'Approved' }} 39 | @else 40 | {{ 'Pending Approval' }} 41 | @endif 42 |
48 | @else 49 |

There are no leave applications for this user yet!

50 | @endif 51 |
52 |
53 |
54 | 55 | @endsection 56 | 57 | @endsection -------------------------------------------------------------------------------- /resources/views/welcome.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 | 5 |
6 | {{-- --}} 7 |
8 | 9 | @endsection -------------------------------------------------------------------------------- /routes/api.php: -------------------------------------------------------------------------------- 1 | get('/user', function (Request $request) { 17 | return $request->user(); 18 | }); 19 | -------------------------------------------------------------------------------- /routes/channels.php: -------------------------------------------------------------------------------- 1 | id === (int) $id; 16 | }); 17 | -------------------------------------------------------------------------------- /routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 18 | })->describe('Display an inspiring quote'); 19 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | route('login'); 9 | }); 10 | 11 | Route::middleware(['auth'])->group(function () { 12 | Route::get('/home', 'HomeController@index')->name('home'); 13 | Route::get('/users', 'AdminController@index')->name('all-admins'); 14 | 15 | Route::middleware(['user.type'])->group(function () { 16 | Route::get('/staff', 'StaffController@index')->name('all-staff-members'); 17 | Route::get('/staff/create', 'StaffController@create')->name('new-staff'); 18 | Route::post('/staff', ['uses' => 'StaffController@store', 'as' => 'add-new-staff']); 19 | Route::delete('/staff/{staff}',['uses' => 'StaffController@delete', 'as' => 'delete-staff']); 20 | 21 | Route::get('/create/{staff}/message', 'MessageController@createMessage')->name('email-staff'); 22 | 23 | Route::get('/payslips/{staff}/create', ['uses' => 'PayslipController@create', 'as' => 'create-staff-payroll']); 24 | Route::post('/payslips', ['uses' => 'PayslipController@store', 'as' => 'store-staff-payroll']); 25 | Route::get('/payslips', 'PayslipController@index')->name('all-staff-members-payroll'); 26 | 27 | Route::post('/send/message', 'MessageController@sendMessage')->name('send-staff-message'); 28 | Route::get('/send/{staff}/payroll/{payroll}', ['uses' => 'MessageController@sendStaffPayroll', 'as' => 'send-staff-payroll']); 29 | Route::get('/pending/leave', 'StaffLeaveController@allPendingLeave')->name('pending-leave'); 30 | Route::get('/approved/leave', 'StaffLeaveController@allApprovedLeave')->name('approved-leave'); 31 | Route::post('/approve/leave', 'StaffLeaveController@approveLeave')->name('admin-approve-leave'); 32 | }); 33 | 34 | Route::get('/staff/{staff}',['uses' => 'StaffController@show', 'as' => 'show-staff']); 35 | Route::get('/staff/{staff}/edit',['uses' => 'StaffController@edit', 'as' => 'edit-staff']); 36 | Route::put('/staff/{staff}', ['uses' => 'StaffController@update', 'as' => 'update-staff']); 37 | 38 | Route::get('/leave/create', 'StaffLeaveController@create')->name('apply.leave'); 39 | Route::post('/leave', 'StaffLeaveController@store')->name('store.leave'); 40 | Route::get('/staff/{staff}/leave', 'StaffLeaveController@staffLeaves')->name('my-leave'); 41 | }); 42 | -------------------------------------------------------------------------------- /server.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | 10 | $uri = urldecode( 11 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) 12 | ); 13 | 14 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the 15 | // built-in PHP web server. This provides a convenient way to test a Laravel 16 | // application without having installed a "real" web server software here. 17 | if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) { 18 | return false; 19 | } 20 | 21 | require_once __DIR__.'/public/index.php'; 22 | -------------------------------------------------------------------------------- /storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !public/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /storage/app/public/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/.gitignore: -------------------------------------------------------------------------------- 1 | config.php 2 | routes.php 3 | schedule-* 4 | compiled.php 5 | services.json 6 | events.scanned.php 7 | routes.scanned.php 8 | down 9 | -------------------------------------------------------------------------------- /storage/framework/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/sessions/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/testing/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /tests/CreatesApplication.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class)->bootstrap(); 19 | 20 | return $app; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/Feature/PayrollTest.php: -------------------------------------------------------------------------------- 1 | disableExceptionHandling(); 21 | } 22 | 23 | 24 | 25 | /** @test */ 26 | public function an_authenticated_admin_can_view_form_for_creating_staff_payslip() 27 | { 28 | $user = $this->actingAs($this->factoryWithoutObservers(User::class)->create(['is_admin' => true])); 29 | $this->factoryWithoutObservers(Staff::class)->create(); 30 | 31 | $staff = Staff::first(); 32 | 33 | $response = $user->get('/payslips/'.$staff->id.'/create'); 34 | $response->assertStatus(200); 35 | $response->assertViewIs("create-payslip"); 36 | 37 | } 38 | 39 | 40 | /** @test */ 41 | public function an_authenticated_admin_can_add_staff_payslip() 42 | { 43 | $user = $this->actingAs($this->factoryWithoutObservers(User::class)->create(['is_admin' => true])); 44 | $staff = $this->factoryWithoutObservers(Staff::class)->create(['user_id' => auth()->id()]); 45 | 46 | $pay_slip_details = [ 47 | 'staff_id' => $staff->id, 48 | 'gross_salary' => 100000, 49 | 'tax_percentage' => 10, 50 | 'net_salary' => 10000, 51 | 'month' => 'January', 52 | 'year' => 2019 53 | ]; 54 | 55 | $response = $user->post('/payslips', $pay_slip_details); 56 | $response->assertStatus(302); 57 | $payslip = Payroll::first(); 58 | $this->assertEquals(100000,$payslip->gross_salary); 59 | $this->assertDatabaseHas('payrolls', $pay_slip_details); 60 | 61 | } 62 | 63 | 64 | 65 | /** @test */ 66 | public function an_authenticated_admin_can_view_all_staff_payslips() 67 | { 68 | $user = $this->actingAs($this->factoryWithoutObservers(User::class)->create(['is_admin' => true])); 69 | $this->factoryWithoutObservers(Staff::class)->create(); 70 | $this->factoryWithoutObservers(Payroll::class, 5)->create(); 71 | $payslip = $this->factoryWithoutObservers(Payroll::class)->create([ 72 | 'gross_salary' => 14000 73 | ]); 74 | 75 | $response = $user->get('/payslips'); 76 | $response->assertStatus(200); 77 | $response->assertViewHas('payrolls'); 78 | $response->assertSeeText("14000"); 79 | 80 | 81 | } 82 | 83 | 84 | 85 | 86 | 87 | } 88 | -------------------------------------------------------------------------------- /tests/Feature/UserTest.php: -------------------------------------------------------------------------------- 1 | disableExceptionHandling(); 17 | } 18 | 19 | 20 | 21 | /** @test */ 22 | public function an_authenticated_admin_can_view_all_admins() 23 | { 24 | $user = $this->factoryWithoutObservers(User::class)->create(); 25 | $user = $this->actingAs($user); 26 | $this->factoryWithoutObservers(User::class, 5); 27 | $admin = $this->factoryWithoutObservers(User::class)->create([ 28 | 'name' => 'Aliu' 29 | ]); 30 | 31 | $response = $user->get('/users'); 32 | $response->assertStatus(200); 33 | $response->assertViewIs("all-admin-members"); 34 | $response->assertViewHas("admins"); 35 | $response->assertSeeText("Aliu"); 36 | 37 | } 38 | 39 | 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | app->instance(ExceptionHandler::class, new class extends Handler { 29 | public function __construct() {} 30 | 31 | public function report(Exception $e) 32 | { 33 | // no-op 34 | } 35 | 36 | public function render($request, Exception $e) { 37 | throw $e; 38 | } 39 | }); 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /tests/Unit/ExampleTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/Unit/SendGeneralMessageToStaffTest.php: -------------------------------------------------------------------------------- 1 | disableExceptionHandling(); 21 | 22 | } 23 | 24 | 25 | 26 | /** @test */ 27 | public function an_authenticated_admin_can_send_message_to_staff() 28 | { 29 | $user = $this->actingAs($this->factoryWithoutObservers(User::class)->create(['is_admin' => true])); 30 | $staff = $this->factoryWithoutObservers(Staff::class)->create([ 31 | 'user_id' => auth()->id() 32 | ]); 33 | $message = [ 34 | 'id' => $staff->id, 35 | 'email' => 'aliuwahab@gmail.com', 36 | 'subject' => 'Sample Subject', 37 | 'content' => 'Sample Message Content' 38 | ]; 39 | 40 | $response = $user->post("/send/message",$message); 41 | 42 | 43 | $response->assertStatus(302); 44 | $staff_auth_account = Staff::with('user')->find($staff->id); 45 | $this->seeEmailSubject($message['subject']); 46 | $this->seeEmailTo($staff_auth_account->user->email); 47 | $this->seeEmailContains($message['content']); 48 | 49 | } 50 | 51 | 52 | 53 | 54 | 55 | 56 | } 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /tests/Unit/SendPayslipTest.php: -------------------------------------------------------------------------------- 1 | disableExceptionHandling(); 22 | } 23 | 24 | /** @test */ 25 | public function an_authenticated_admin_can_send_payslip_as_message_to_staff() 26 | { 27 | 28 | $user = $this->actingAs($this->factoryWithoutObservers(User::class)->create(['is_admin' => true])); 29 | $this->factoryWithoutObservers(Staff::class)->create(); 30 | $payslip = $this->factoryWithoutObservers(Payroll::class)->create(); 31 | 32 | $staff = Staff::with('user')->first(); 33 | $response = $user->get('send/'.$staff->id.'/payroll/'.$payslip->id); 34 | $response->assertStatus(302); 35 | 36 | $this->seeEmailTo($staff->user->email); 37 | $this->seeEmailSubject("Your Invoice for " . $payslip->month . " " . $payslip->year); 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /webpack.mix.js: -------------------------------------------------------------------------------- 1 | let mix = require('laravel-mix'); 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | Mix Asset Management 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Mix provides a clean, fluent API for defining some Webpack build steps 9 | | for your Laravel application. By default, we are compiling the Sass 10 | | file for the application as well as bundling up all the JS files. 11 | | 12 | */ 13 | 14 | mix.js('resources/assets/js/app.js', 'public/js') 15 | .sass('resources/assets/sass/app.scss', 'public/css'); 16 | --------------------------------------------------------------------------------