From 65493e6c901ac62bfdf3dde5f93df02b6ac903d9 Mon Sep 17 00:00:00 2001 From: omair saleh Date: Wed, 22 Sep 2021 14:14:47 +0800 Subject: [PATCH 1/5] invitation link registration --- .../CreateInvitedCustomerLogic.php | 105 ++++++++++++++++++ .../CreateInvitedCustomerController.php | 20 ++++ app/Http/Resources/CompanyResource.php | 2 + .../forms/InviteRegistrationFormComponent.vue | 101 +++++++++++++++++ .../RegistrationCheckEmailFormComponent.vue | 1 - .../forms/RegistrationFormComponent.vue | 1 - .../elements/CustomerProfileComponent.vue | 10 ++ .../inviteRegistrationFormValidation.js | 27 +++++ resources/assets/vue/general/mixins/guards.js | 5 +- .../assets/vue/general/mixins/stepNavi.js | 22 ---- .../pages/accounts/claim_business.blade.php | 23 ++++ routes/account.php | 1 + routes/web.php | 13 ++- 13 files changed, 300 insertions(+), 31 deletions(-) create mode 100644 app/Classes/Modules/Accounts/ControllersLogic/CreateInvitedCustomerLogic.php create mode 100644 app/Http/Controllers/Accounts/CreateInvitedCustomerController.php create mode 100644 resources/assets/vue/components/accounts/forms/InviteRegistrationFormComponent.vue create mode 100644 resources/assets/vue/general/mixins/accounts/validation/inviteRegistrationFormValidation.js delete mode 100644 resources/assets/vue/general/mixins/stepNavi.js create mode 100644 resources/views/pages/accounts/claim_business.blade.php diff --git a/app/Classes/Modules/Accounts/ControllersLogic/CreateInvitedCustomerLogic.php b/app/Classes/Modules/Accounts/ControllersLogic/CreateInvitedCustomerLogic.php new file mode 100644 index 00000000..ebd4587e --- /dev/null +++ b/app/Classes/Modules/Accounts/ControllersLogic/CreateInvitedCustomerLogic.php @@ -0,0 +1,105 @@ + 'Created User', + 'message' => 'You have successfully created a new User' + ]; + } + + /** @var CreateUserProcessor */ + private $createUserProcessor; + + /** @var CreateContactProcessor */ + private $createContactProcessor; + + /** @var FetchesCompany */ + private $fetchesCompany; + + /** @var AssignEmployeeProcessor */ + private $assignEmployeeProcessor; + + /** @var AuthenticationProcessor */ + private $authenticationProcessor; + + + /** + * CreateInvitedCustomerLogic constructor. + * @param CreateUserProcessor $createUserProcessor + * @param CreateContactProcessor $createContactProcessor + * @param FetchesCompany $fetchesCompany + * @param AssignEmployeeProcessor $assignEmployeeProcessor + * @param AuthenticationProcessor $authenticationProcessor + */ + public function __construct(CreateUserProcessor $createUserProcessor, CreateContactProcessor $createContactProcessor, FetchesCompany $fetchesCompany, AssignEmployeeProcessor $assignEmployeeProcessor, AuthenticationProcessor $authenticationProcessor) + { + $this->createUserProcessor = $createUserProcessor; + $this->createContactProcessor = $createContactProcessor; + $this->fetchesCompany = $fetchesCompany; + $this->assignEmployeeProcessor = $assignEmployeeProcessor; + $this->authenticationProcessor = $authenticationProcessor; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\AccessUnauthorisedException + * @throws \App\Classes\Exceptions\MalformedRequestException + * @throws \App\Classes\Exceptions\RequestValidationException + */ + public function logic(Request $request): JsonResponse + { + /** @var Company $company */ + $company = $this->fetchesCompany->execute(['id' => $request->input('company_id')]); + + /** @var CompanyModule $companyModule */ + $companyModule = $company->companyModules()->first(); + + if($companyModule->employees()->exists()){ + throw new AccessForbiddenException('This company\'s account has been claimed by another user already!'); + } + + /** @var User $user */ + $user = $this->createUserProcessor->execute($request, RoleTypes::USER, !App::environment(['production']) ? ApprovalStatus::APPROVED : ApprovalStatus::PENDING_VERIFICATION); + + $contactObject = new ContactObject($request->input('name'), $request->input('phone'), $request->input('contact_email'), $request->input('wechat_id')); + + $this->createContactProcessor->execute($contactObject, $company); + + $Object = new EmploymentObject($companyModule, $user); + + $this->assignEmployeeProcessor->execute($Object); + + return $this->response($this->authenticationProcessor->execute($request)); + } +} diff --git a/app/Http/Controllers/Accounts/CreateInvitedCustomerController.php b/app/Http/Controllers/Accounts/CreateInvitedCustomerController.php new file mode 100644 index 00000000..dce70e1e --- /dev/null +++ b/app/Http/Controllers/Accounts/CreateInvitedCustomerController.php @@ -0,0 +1,20 @@ +execute($request); + } +} \ No newline at end of file diff --git a/app/Http/Resources/CompanyResource.php b/app/Http/Resources/CompanyResource.php index 702319aa..cae286b9 100644 --- a/app/Http/Resources/CompanyResource.php +++ b/app/Http/Resources/CompanyResource.php @@ -11,6 +11,7 @@ use App\Models\CompanyModule; use App\Models\Currency; use App\Models\SegmentConstant; use Illuminate\Http\Resources\Json\JsonResource; +use Illuminate\Support\Facades\Crypt; class CompanyResource extends JsonResource { @@ -25,6 +26,7 @@ class CompanyResource extends JsonResource $companyModule = $this->companyModules()->where('type', '=', BusinessType::IMPORTER)->first(); return [ 'id' => $this->id, + 'hash_id' => Crypt::encryptString($this->id), 'name' => $this->name, 'reference' => $this->reference, 'type' => (int) $this->type, diff --git a/resources/assets/vue/components/accounts/forms/InviteRegistrationFormComponent.vue b/resources/assets/vue/components/accounts/forms/InviteRegistrationFormComponent.vue new file mode 100644 index 00000000..9b8af5ea --- /dev/null +++ b/resources/assets/vue/components/accounts/forms/InviteRegistrationFormComponent.vue @@ -0,0 +1,101 @@ + + diff --git a/resources/assets/vue/components/accounts/forms/RegistrationCheckEmailFormComponent.vue b/resources/assets/vue/components/accounts/forms/RegistrationCheckEmailFormComponent.vue index e96c3f46..04a74241 100644 --- a/resources/assets/vue/components/accounts/forms/RegistrationCheckEmailFormComponent.vue +++ b/resources/assets/vue/components/accounts/forms/RegistrationCheckEmailFormComponent.vue @@ -38,7 +38,6 @@ \ No newline at end of file diff --git a/resources/assets/vue/general/mixins/accounts/validation/inviteRegistrationFormValidation.js b/resources/assets/vue/general/mixins/accounts/validation/inviteRegistrationFormValidation.js new file mode 100644 index 00000000..7879ff6d --- /dev/null +++ b/resources/assets/vue/general/mixins/accounts/validation/inviteRegistrationFormValidation.js @@ -0,0 +1,27 @@ +import { required, email, numeric, sameAs, requiredUnless, requiredIf } from "vuelidate/lib/validators"; +import authenticationHandler from '../authenticationHandler' +export default { + validations: { + parameters: { + name: { + required: required + }, + email: { + required: required, + email + }, + phone: { + required: required, + numeric + }, + password: { + required: required, + }, + password_confirmation: { + required: required, + sameAs: sameAs('password') + } + } + }, + mixins: [authenticationHandler] +} \ No newline at end of file diff --git a/resources/assets/vue/general/mixins/guards.js b/resources/assets/vue/general/mixins/guards.js index 18681e5d..ffa96e7d 100644 --- a/resources/assets/vue/general/mixins/guards.js +++ b/resources/assets/vue/general/mixins/guards.js @@ -5,7 +5,10 @@ export default { (this.$store.getters.isAuthenticated && !this.isProtectedRoute()&& this.isWithTokenRoute()) ? window.location.href = this.route('dashboard') : ''; }, isProtectedRoute(){ - const unprotectedRoutes = [this.route('login'), this.route('account.email.verification')]; + const unprotectedRoutes = [this.route('login'), this.route('account.email.verification'), this.route('company.claim')]; + if(window.location.href.indexOf(this.route('company.claim')) === 0) { + return false; + } return !unprotectedRoutes.includes(window.location.href); }, isWithTokenRoute(){ diff --git a/resources/assets/vue/general/mixins/stepNavi.js b/resources/assets/vue/general/mixins/stepNavi.js deleted file mode 100644 index a3c05a0d..00000000 --- a/resources/assets/vue/general/mixins/stepNavi.js +++ /dev/null @@ -1,22 +0,0 @@ -export default { - methods: { - changeStep(direction) { - this.status.direction = direction; - - if (direction === 'next') { - - if (this.validate()) { - //this.step += 1; - this.status.email = this.parameters.email; - this.$emit('updateStatus', this.status); - } - return; - } - this.$emit('updateStatus', this.status); - this.$v.$reset(); - }, - }, - beforeDestroy: function (event) { - }, - -} \ No newline at end of file diff --git a/resources/views/pages/accounts/claim_business.blade.php b/resources/views/pages/accounts/claim_business.blade.php new file mode 100644 index 00000000..645b8e5f --- /dev/null +++ b/resources/views/pages/accounts/claim_business.blade.php @@ -0,0 +1,23 @@ +@extends('layouts.base_login') + +@section('inner_content') +
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+
+@endsection \ No newline at end of file diff --git a/routes/account.php b/routes/account.php index 7a9e08df..ff6a9960 100644 --- a/routes/account.php +++ b/routes/account.php @@ -5,6 +5,7 @@ use Illuminate\Support\Facades\Route; Route::group(['prefix' => 'account', 'namespace' => 'Accounts', 'as' => 'account.'], function () { Route::post('/registration', 'CreateCustomerController@create')->name('registration.register'); + Route::post('/invite/registration', 'CreateInvitedCustomerController@create')->name('registration.invite.register'); Route::group(['prefix' => 'authentication', 'as' => 'authentication.'], function () { Route::group(['prefix' => 'login', 'as' => 'authenticate.'], function () { diff --git a/routes/web.php b/routes/web.php index 2eb2bcbb..0e1b6593 100644 --- a/routes/web.php +++ b/routes/web.php @@ -6,6 +6,7 @@ use App\Classes\Jobs\FetchLoadedContainersFromVTPortalJob; use App\Classes\Jobs\FetchPackingListFromVTPortalJob; use App\Classes\Jobs\FetchWarehouseReceiveListFromVTPortalJob; use App\Models\CompanyConnection; +use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Facades\Route; /* @@ -21,9 +22,9 @@ use Illuminate\Support\Facades\Route; require __DIR__ . '/template.php'; -Route::get('/', function () { - return view('welcome'); -}); +Route::get('', function () { + return view('pages.accounts.login'); +})->name('login'); Route::group(['prefix' => 'swagger'], function () { Route::get('/', function () { @@ -34,9 +35,9 @@ Route::group(['prefix' => 'swagger'], function () { }); }); -Route::get('', function () { - return view('pages.accounts.login');//temporary showing welcome page. -})->name('login'); +Route::get('/business/claim/{hash}', function ($hash) { + return view('pages.accounts.claim_business', ['id' => Crypt::decryptString($hash)]); +})->name('company.claim'); Route::get('/account/email/verification/{token}', function ($token) { return view('pages.accounts.email_verified', ['token' => $token]); From a8e26c4dd6bd2f81ce29b63c5f7368d1c4a53100 Mon Sep 17 00:00:00 2001 From: omair saleh Date: Wed, 22 Sep 2021 14:20:50 +0800 Subject: [PATCH 2/5] invitation link registration --- .../components/companies/elements/CustomerProfileComponent.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/assets/vue/components/companies/elements/CustomerProfileComponent.vue b/resources/assets/vue/components/companies/elements/CustomerProfileComponent.vue index b0e28553..b68875d3 100644 --- a/resources/assets/vue/components/companies/elements/CustomerProfileComponent.vue +++ b/resources/assets/vue/components/companies/elements/CustomerProfileComponent.vue @@ -41,7 +41,7 @@
-
Account Owner
+
Email Address
{{item.employee.email}}
From 8039446db56715f6686b29b352081d5784801e6d Mon Sep 17 00:00:00 2001 From: omair saleh Date: Wed, 22 Sep 2021 14:57:29 +0800 Subject: [PATCH 3/5] tooltip for copying invitation link --- .../companies/elements/CustomerProfileComponent.vue | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/resources/assets/vue/components/companies/elements/CustomerProfileComponent.vue b/resources/assets/vue/components/companies/elements/CustomerProfileComponent.vue index b68875d3..af3e0e7c 100644 --- a/resources/assets/vue/components/companies/elements/CustomerProfileComponent.vue +++ b/resources/assets/vue/components/companies/elements/CustomerProfileComponent.vue @@ -112,7 +112,7 @@
Claimed
-
+
Invitation Link
@@ -126,9 +126,16 @@ import componentHandler from '../../../general/mixins/componentHandler'; export default { methods: { - copyUrl() { + copyUrl(event) { this.$refs.invitationLink.select(); document.execCommand('copy'); + + $(this.$refs.copyButton).tooltip({ + title: 'Url Copied To Clipboard!', + placement: 'left', + delay: 1000 + }); + $(this.$refs.copyButton).tooltip('show'); } }, mixins: [componentHandler] From 9719f1da778adbf217dc1d8cf0c854d882c4125f Mon Sep 17 00:00:00 2001 From: omair saleh Date: Thu, 23 Sep 2021 18:34:53 +0800 Subject: [PATCH 4/5] show container total cbm --- app/Http/Resources/ContainerResource.php | 3 ++- .../vue/components/containers/elements/ContainerComponent.vue | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/Http/Resources/ContainerResource.php b/app/Http/Resources/ContainerResource.php index 774ada84..bc6337cc 100644 --- a/app/Http/Resources/ContainerResource.php +++ b/app/Http/Resources/ContainerResource.php @@ -2,6 +2,7 @@ namespace App\Http\Resources; +use App\Classes\ValueObjects\Constants\ContainerTypes; use Illuminate\Http\Resources\Json\JsonResource; class ContainerResource extends JsonResource @@ -17,7 +18,7 @@ class ContainerResource extends JsonResource return [ 'id' => $this->id, 'container_reference' => $this->reference, - 'container_type' => $this->container_type, + 'container_specification' => ContainerTypes::CONTAINER_SPECIFICATION[$this->container_type], 'container_number' => $this->container_number, 'seal_reference' => $this->seal_reference, 'transport' => new TransportResource($this->transports()->first()), diff --git a/resources/assets/vue/components/containers/elements/ContainerComponent.vue b/resources/assets/vue/components/containers/elements/ContainerComponent.vue index e8af2c65..d02e69a6 100644 --- a/resources/assets/vue/components/containers/elements/ContainerComponent.vue +++ b/resources/assets/vue/components/containers/elements/ContainerComponent.vue @@ -22,6 +22,10 @@

ETA

{{item.transport ? item.transport.current_schedule.eta : 'n/a'}}

+
+

Loaded CBM

+

{{ (Math.ceil((item.packing_lists.reduce((total, obj) => total + obj.packages.reduce((total, obj) => obj.cbm + total, 0), 0)) * 1000) / 1000).toFixed(3) }}

+

Status

{{item.status === 3 ? 'Un-stuffed' : 'In Progress'}}

From 09f598ffe53104c3e715dde6dc39d441620e1327 Mon Sep 17 00:00:00 2001 From: omair saleh Date: Thu, 23 Sep 2021 18:35:58 +0800 Subject: [PATCH 5/5] show container total cbm --- .../vue/components/containers/elements/ContainerComponent.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/assets/vue/components/containers/elements/ContainerComponent.vue b/resources/assets/vue/components/containers/elements/ContainerComponent.vue index d02e69a6..6ab36156 100644 --- a/resources/assets/vue/components/containers/elements/ContainerComponent.vue +++ b/resources/assets/vue/components/containers/elements/ContainerComponent.vue @@ -22,7 +22,7 @@

ETA

{{item.transport ? item.transport.current_schedule.eta : 'n/a'}}

-
+

Loaded CBM

{{ (Math.ceil((item.packing_lists.reduce((total, obj) => total + obj.packages.reduce((total, obj) => obj.cbm + total, 0), 0)) * 1000) / 1000).toFixed(3) }}