Compare commits

...

29 Commits

Author SHA1 Message Date
Dillon bffe438455 Disable help menu 2023-10-16 01:09:24 +08:00
Dillon f5482a29e4 New exception handling for all PerfexCRM services 2023-10-08 17:23:55 +08:00
Dillon 5584d22376 Improvement to log capture thrown by custom exception (ConnectionErrorException), to evaluate if need to extend to other custom exception as well 2023-10-05 19:58:07 +08:00
Dillon 42b6140df7 UX update when system failed to open a support ticket via help menu 2023-10-05 17:30:29 +08:00
Dillon 619fc25605 Merge branch 'dillon/44-customer-satisfaction-feedback-project' into dillon/44-customer-satisfaction-feedback-project-b 2023-10-05 17:04:41 +08:00
Dillon 8c24c86c77 Extra log to capture when ticket not created from Help Menu 2023-10-05 17:02:34 +08:00
Dillon 822046cc69 Updated comments in code 2023-10-05 16:52:42 +08:00
Dillon d708b8b540 404 page when feedback form not found 2023-10-05 16:41:21 +08:00
Dillon 0f7f5f7ab9 Shorten feedback url 2023-10-04 01:34:45 +08:00
Dillon a5c1ae14b7 Shorten feedback url 2023-10-04 01:02:19 +08:00
Omair Saleh 8f5aa0a861 change ui for feedback answers to use columns instead of rows 2023-10-03 16:11:46 +08:00
Omair Saleh 1bed7f1cc9 change ui for feedback answers to use columns instead of rows 2023-10-03 14:09:46 +08:00
Omair Saleh 0a16e40a23 change ui for feedback answers to use columns instead of rows 2023-10-03 13:53:21 +08:00
Dillon 5c24b6f81e Relocate help menu and make dynamic questionnaire set generation 2023-10-01 00:32:40 +08:00
Dillon b81f3e50ad Filter out help menu questions and answers from been listed in admin feedback q&a list + disabled help menu 2023-09-30 18:45:35 +08:00
Dillon 5d07598c5e Meeting feedback Fixes and improvement with new sets of questions for customer feedback 2023-09-29 01:45:24 +08:00
Dillon e4f60a7bff Limit access to certain api query to admin only 2023-09-25 10:55:47 +08:00
Dillon fe000b7a6f Minor UI fix on front end 2023-09-23 18:07:46 +08:00
Dillon 707ef9d9f3 Minor UI fix on /feedback admin page 2023-09-23 17:36:46 +08:00
Dillon b5abb04c63 Minor UI fix on /feedback admin page 2023-09-23 16:53:18 +08:00
Dillon 1dbad7d6e5 Minor UI fix on navigation 2023-09-23 16:47:58 +08:00
Dillon fe67cc6c5b Rename 2023-09-21 20:35:14 +08:00
Dillon 90b85c0df1 Rename 2023-09-21 20:16:22 +08:00
Dillon 0cdff7c544 Fix a problem customer marking cannot be found 2023-09-21 08:04:33 +08:00
Dillon 42561a7c56 New Customer Satisfaction Feedback Module 2023-09-21 00:19:21 +08:00
Dillon 60fbe77829 Merge branch 'dillon/crisp-help-menu-2' into dillon/44-customer-satisfaction-feedback-project 2023-09-14 10:28:04 +08:00
Dillon 18579d5c1d Implement help menu on new order profile version 2 component 2023-05-04 15:42:16 +08:00
Dillon 1060401128 Merge branch 'dillon/crisp-help-menu' into dillon/crisp-help-menu-2 2023-05-04 15:39:54 +08:00
Dillon 5b00b7b45f Help Menu prototype v0.1 2023-05-04 15:19:04 +08:00
111 changed files with 4624 additions and 52 deletions
@@ -0,0 +1,20 @@
<?php
namespace App\Classes\Exceptions;
use App\Classes\ValueObjects\Constants\HttpStatus;
use Illuminate\Support\Facades\Log;
final class ConnectionErrorException extends ServiceApiException {
public function __construct(?string $message = null, ?string $exceptionMessage = null, ?string $payload = null, ?string $exceptionTrace = null) {
Log::error($message. ": ". $exceptionMessage);
if($payload){
Log::error('Payload: '.$payload);
}
if($exceptionTrace){
Log::error($exceptionTrace);
}
parent::__construct($message ?? 'A connection error has occurred. Please check application logs for more information.',
HttpStatus::SERVER_ERROR);
}
}
@@ -0,0 +1,22 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class HasQuestionnaireGroupIn implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->whereHas('question.questionnaire', function (Builder $query) use ($value) {
$query->whereIn('group', $value);
});
}
}
@@ -0,0 +1,18 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class IdNext implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('id', '>', $value);
}
}
@@ -0,0 +1,18 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class NextMainQuestion implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('next_main_question', $value);
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class QuestionId implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('question_id', $value);
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class QuestionNumber implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('question_number', $value);
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class QuestionnaireSetId implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('questionnaire_set_id', $value);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class ShortUrl implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('short_url', $value);
}
}
@@ -0,0 +1,18 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class UserId implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('user_id', $value);
}
}
@@ -0,0 +1,50 @@
<?php
namespace App\Classes\Modules\Documents\Processors;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Models\Document;
use Illuminate\Http\Request;
use App\Models\QAUserAnswerSelected;
class UploadDocumentForHelpMenuProcessor
{
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFiles;
/**
* UploadDocumentForHelpMenuProcessor constructor.
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFiles
*/
public function __construct(CreatesDocument $createsDocument, CreatesFiles $createsFiles)
{
$this->createsDocument = $createsDocument;
$this->createsFiles = $createsFiles;
}
/**
* @param $filesUpload
* @param QAUserAnswerSelected qaUserAnswerSelected
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute($filesUpload, QAUserAnswerSelected $qaUserAnswerSelected) {
$object = new DocumentObject("HELP_MENU", $filesUpload,
'123456', ApprovalStatus::PENDING_VERIFICATION, 'help_menu'); //cief todo: 123456 cannot be hardcoded
/** @var Document $document */
$document = $this->createsDocument->execute($qaUserAnswerSelected, $object);
$result = $this->createsFiles->execute($document, $object);
return $result;
}
}
@@ -0,0 +1,62 @@
<?php
namespace App\Classes\Modules\HelpMenu\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\HelpMenu\Standards\Rules\CanFetchHelpMenuQuestion;
use App\Classes\Modules\HelpMenu\Processors\FetchFirstQuestionQAProcessor;
use App\Http\Resources\HelpMenuQuestionResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class FetchQuestionQALogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Help Menu First Question',
'message' => 'You have successfully retrieved a Help Menu First Question'
];
}
/** @var CanFetchHelpMenuQuestion */
private $canFetchHelpMenuQuestion;
/** @var FetchFirstQuestionQAProcessor */
private $fetchFirstQuestionQAProcessor;
/**
* FetchQuestionQALogic constructor.
* @param CanFetchHelpMenuQuestion $canFetchHelpMenuQuestion
* @param FetchFirstQuestionQAProcessor $fetchFirstQuestionQAProcessor
*/
public function __construct(CanFetchHelpMenuQuestion $canFetchHelpMenuQuestion, FetchFirstQuestionQAProcessor $fetchFirstQuestionQAProcessor)
{
$this->canFetchHelpMenuQuestion = $canFetchHelpMenuQuestion;
$this->fetchFirstQuestionQAProcessor = $fetchFirstQuestionQAProcessor;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$this->canFetchHelpMenuQuestion->passes();
$userId = Auth::user()->id;
$query = $this->fetchFirstQuestionQAProcessor->execute($request);
return $this->resourceResponse(new HelpMenuQuestionResource($query, $userId));
}
}
@@ -0,0 +1,67 @@
<?php
namespace App\Classes\Modules\HelpMenu\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\HelpMenu\DataTransferObjects\UrlObject;
use App\Classes\Modules\HelpMenu\Standards\Rules\CanGenerateFeedbackUrl;
use App\Classes\Modules\HelpMenu\Services\CreatesUrl;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Str;
class GenerateFeedbackUrlLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Generate Feedback Url',
'message' => 'You have successfully generated a feedback url'
];
}
/** @var CanGenerateFeedbackUrl */
private $canGenerateFeedbackUrl;
/** @var CreatesUrl */
private $createsUrl;
/**
* GenerateFeedbackUrlLogic constructor.
* @param CanGenerateFeedbackUrl $canGenerateFeedbackUrl
* @param CreatesUrl $createsUrl
*/
public function __construct(CanGenerateFeedbackUrl $canGenerateFeedbackUrl, CreatesUrl $createsUrl)
{
$this->canGenerateFeedbackUrl = $canGenerateFeedbackUrl;
$this->createsUrl = $createsUrl;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$this->canGenerateFeedbackUrl->passes();
$shortUrl = Str::random(20);
$originalText = $request->input('system') . '|' . $request->input('customer_marking'). '|' . $request->input('email'). '|' . $request->input('question_set') . '|' . $shortUrl;
$originalUrl = Crypt::encryptString($originalText);
$url = $this->createsUrl->execute(new UrlObject('feedback', $shortUrl, $originalUrl));
$resource = ['token' => $url->short_url];
return $this->response(['data' => $resource]);
}
}
@@ -0,0 +1,60 @@
<?php
namespace App\Classes\Modules\HelpMenu\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\HelpMenu\Services\ListsHelpMenuUserAnswerSelected;
use App\Classes\Modules\HelpMenu\Standards\Rules\CanListHelpMenuQuestions;
use App\Http\Resources\HelpMenuQuestionsAnswersResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListQuestionsAnswersQALogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Questions Answers',
'message' => 'You have successfully retrieved a list of questions and answers'
];
}
/** @var CanListHelpMenuQuestions */
private $canListHelpMenuQuestions;
/** @var ListsHelpMenuUserAnswerSelected */
private $listsHelpMenuUserAnswerSelected;
/**
* ListQuestionsAnswersQALogic constructor.
* @param CanListHelpMenuQuestions $canListHelpMenuQuestions
* @param ListsHelpMenuUserAnswerSelected $listsHelpMenuUserAnswerSelected
*/
public function __construct(CanListHelpMenuQuestions $canListHelpMenuQuestions, ListsHelpMenuUserAnswerSelected $listsHelpMenuUserAnswerSelected)
{
$this->canListHelpMenuQuestions = $canListHelpMenuQuestions;
$this->listsHelpMenuUserAnswerSelected = $listsHelpMenuUserAnswerSelected;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request) : JsonResponse
{
$this->canListHelpMenuQuestions->passes();
$query = $this->listsHelpMenuUserAnswerSelected->execute($this->listsHelpMenuUserAnswerSelected->deserializeFilters($request->input('filters')));
return $this->collectionResponse(HelpMenuQuestionsAnswersResource::collection($query));
}
}
@@ -0,0 +1,66 @@
<?php
namespace App\Classes\Modules\HelpMenu\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\HelpMenu\Services\ListsHelpMenuQuestions;
use App\Classes\Modules\HelpMenu\Services\FetchesUrl;
use App\Http\Resources\HelpMenuQuestionResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
use App\Classes\Exceptions\ResourceNotFoundException;
class ListQuestionsQALogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Questions',
'message' => 'You have successfully retrieved a list of Questions'
];
}
/** @var ListsHelpMenuQuestions */
private $listsHelpMenuQuestions;
/** @var FetchesUrl */
private $fetchesUrl;
/**
* ListQuestionsQALogic constructor.
* @param ListsHelpMenuQuestions $listsHelpMenuQuestions
* @param FetchesUrl $fetchesUrl
*/
public function __construct(ListsHelpMenuQuestions $listsHelpMenuQuestions, FetchesUrl $fetchesUrl)
{
$this->listsHelpMenuQuestions = $listsHelpMenuQuestions;
$this->fetchesUrl = $fetchesUrl;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
* @throws \App\Classes\Exceptions\ResourceNotFoundException
*/
public function logic(Request $request) : JsonResponse
{
$url = $this->fetchesUrl->execute(['short_url' => $request->input('token')]);
$token = $url->original_url;
$decriptedToken = Crypt::decryptString($token);
$delimiter = "|";
$parts = explode($delimiter, $decriptedToken);
$questionSet = $parts[3];
$query = $this->listsHelpMenuQuestions->execute(['questionnaire_set_id' => $questionSet]);
return $this->collectionResponse(HelpMenuQuestionResource::collection($query));
}
}
@@ -0,0 +1,89 @@
<?php
namespace App\Classes\Modules\HelpMenu\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\HelpMenu\Processors\SaveAnswerProcessor;
use App\Classes\Modules\HelpMenu\Processors\UserSourceForQAProcessor;
use App\Classes\Modules\HelpMenu\Services\FetchesUrl;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Crypt;
class SubmitQAQuestionsLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Feedback Submission',
'message' => 'You have successfully submitted yours answers'
];
}
/** @var SaveAnswerProcessor */
private $saveAnswerProcessor;
/** @var UserSourceForQAProcessor */
private $userSourceForQAProcessor;
/** @var FetchesUrl */
private $fetchesUrl;
/**
* SubmitQAQuestionsLogic constructor.
* @param SaveAnswerProcessor $saveAnswerProcessor
* @param UserSourceForQAProcessor $userSourceForQAProcessor
* @param FetchesUrl $fetchesUrl
*/
public function __construct(SaveAnswerProcessor $saveAnswerProcessor, UserSourceForQAProcessor $userSourceForQAProcessor, FetchesUrl $fetchesUrl)
{
$this->saveAnswerProcessor = $saveAnswerProcessor;
$this->userSourceForQAProcessor = $userSourceForQAProcessor;
$this->fetchesUrl = $fetchesUrl;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$originalToken = '';
$shortToken = $request->input('token');
$userId = 0;
$sourceId = 0;
try {
$url = $this->fetchesUrl->execute(['short_url' => $shortToken]);
$originalToken = $url->original_url;
$decriptedToken = Crypt::decryptString($originalToken);
$delimiter = "|";
$parts = explode($delimiter, $decriptedToken);
$system = $parts[0];
$customerMarking = $parts[1];
$email = $parts[2];
$result = $this->userSourceForQAProcessor->execute($system, $customerMarking, $email);
$userId = $result['userId'];
$sourceId = $result['sourceId'];
} catch (\Throwable $e) {
Log::error($e);
}
$answers = $request->input('answers');
foreach ($answers as $answer) {
$filesUpload = $request->input('files');
$this->saveAnswerProcessor->execute($userId, $sourceId, $answer['questionId'], $answer['answer'], $answer['answerId'], $filesUpload, $shortToken);
}
$response = ['message' => 'Thank you for your feedback.'];
return $this->response(['data' => $response]);
}
}
@@ -0,0 +1,131 @@
<?php
namespace App\Classes\Modules\HelpMenu\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\PerfexCRM\Services\CreatesPerfexCRMSupportTicket;
use App\Classes\Modules\PerfexCRM\Services\FetchesPerfexCRMCustomer;
use App\Classes\Modules\HelpMenu\Standards\Rules\CanFetchHelpMenuQuestion;
use App\Classes\Modules\HelpMenu\Processors\SaveAnswerProcessor;
use App\Classes\Modules\HelpMenu\Processors\DeleteAnswerQAProcessor;
use App\Classes\Modules\HelpMenu\Processors\FetchNextQuestionQAProcessor;
use App\Classes\Modules\HelpMenu\Processors\FetchFirstQuestionQAProcessor;
use App\Http\Resources\HelpMenuQuestionResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Auth;
use App\Classes\ValueObjects\Constants\QAType;
class UpdateNextQuestionQALogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Help Menu Next Question',
'message' => 'You have successfully retrieved a Help Menu Next Question'
];
}
/** @var CanFetchHelpMenuQuestion */
private $canFetchHelpMenuQuestion;
/** @var SaveAnswerProcessor */
private $saveAnswerProcessor;
/** @var DeleteAnswerQAProcessor */
private $deleteAnswerQAProcessor;
/** @var FetchNextQuestionQAProcessor */
private $fetchNextQuestionQAProcessor;
/** @var FetchFirstQuestionQAProcessor */
private $fetchFirstQuestionQAProcessor;
/** @var CreatesPerfexCRMSupportTicket */
private $createsPerfexCRMSupportTicket;
/** @var FetchesPerfexCRMCustomer */
private $fetchesPerfexCRMCustomer;
/**
* UpdateNextQuestionQALogic constructor.
* @param CanFetchHelpMenuQuestion $canFetchHelpMenuQuestion
* @param SaveAnswerProcessor $saveAnswerProcessor
* @param FetchNextQuestionQAProcessor $fetchNextQuestionQAProcessor
* @param FetchFirstQuestionQAProcessor $fetchFirstQuestionQAProcessor
* @param DeleteAnswerQAProcessor $deleteAnswerQAProcessor
*/
public function __construct(CanFetchHelpMenuQuestion $canFetchHelpMenuQuestion, SaveAnswerProcessor $saveAnswerProcessor, FetchNextQuestionQAProcessor $fetchNextQuestionQAProcessor, FetchFirstQuestionQAProcessor $fetchFirstQuestionQAProcessor, CreatesPerfexCRMSupportTicket $createsPerfexCRMSupportTicket, FetchesPerfexCRMCustomer $fetchesPerfexCRMCustomer, DeleteAnswerQAProcessor $deleteAnswerQAProcessor)
{
$this->canFetchHelpMenuQuestion = $canFetchHelpMenuQuestion;
$this->saveAnswerProcessor = $saveAnswerProcessor;
$this->fetchNextQuestionQAProcessor = $fetchNextQuestionQAProcessor;
$this->fetchFirstQuestionQAProcessor = $fetchFirstQuestionQAProcessor;
$this->createsPerfexCRMSupportTicket = $createsPerfexCRMSupportTicket;
$this->fetchesPerfexCRMCustomer = $fetchesPerfexCRMCustomer;
$this->deleteAnswerQAProcessor = $deleteAnswerQAProcessor;
}
/**
* @param Request $request
* @return JsonResponse
* @throws MalformedRequestException
* @throws ResourceNotFoundException
*/
public function logic(Request $request) : JsonResponse
{
$questionId = 0;
$userId = Auth::user()->id;
$currentQuestion = $request->question;
$questionId = $currentQuestion['id'];
$questionType = $currentQuestion['question_type'];
$this->canFetchHelpMenuQuestion->passes();
//Delete answer
$this->deleteAnswerQAProcessor->execute($userId, $questionId, $request);
//Save answer given by user
if (!$request->has('isPrevious')) {
$filesUpload = $request->input('files');
$answerOptionId = 0;
if ($request->has('answerObj')) {
$answerOptionId = intval($request->answerObj['id']);
}
$answerInText = $request->answer;
$this->saveAnswerProcessor->execute($userId, 0, $questionId, $answerInText, $answerOptionId, $filesUpload);
}
//Create ticket at crm
if (!$request->has('isPrevious')) {
if($questionType == QAType::TICKET_CRM){
$email = Auth::user()->email;
$customer = $this->fetchesPerfexCRMCustomer->execute($email);
$subject = "test subject 3";
$department = 1;
$contactid = 0;
$userid = 0;
if($customer){
$contactid = $customer->id;
$userid = $customer->userid;
}
$this->createsPerfexCRMSupportTicket->execute($subject, $department, $contactid, $userid);
}
}
//Get returned question (previous or next)
$returnQuestion = $this->fetchNextQuestionQAProcessor->execute($request);
//When a questionnaire ended, return back the first question
if(is_null($returnQuestion)){
$returnQuestion = $this->fetchFirstQuestionQAProcessor->execute($request);
}
return $this->resourceResponse(new HelpMenuQuestionResource($returnQuestion, $userId));
}
}
@@ -0,0 +1,55 @@
<?php
namespace App\Classes\Modules\HelpMenu\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class QAUserSourceObject implements DataTransferObject
{
/** @var string */
private $system;
/** @var string */
private $marking;
/** @var string */
private $email;
/**
* QAUserSourceObject constructor.
* @param string $system
* @param string $marking
* @param string $email
*/
public function __construct(string $system, string $marking, string $email)
{
$this->system = $system;
$this->marking = $marking;
$this->email = $email;
}
/**
* @return string
*/
public function getSystem(): string
{
return $this->system;
}
/**
* @return string
*/
public function getMarking(): string
{
return $this->marking;
}
/**
* @return string
*/
public function getEmail(): string
{
return $this->email;
}
}
@@ -0,0 +1,55 @@
<?php
namespace App\Classes\Modules\HelpMenu\DataTransferObjects;
use App\Classes\General\Interfaces\DataTransferObject;
class UrlObject implements DataTransferObject
{
/** @var string */
private $type;
/** @var string */
private $shortUrl;
/** @var string */
private $originalUrl;
/**
* UrlObject constructor.
* @param string $type
* @param string $shortUrl
* @param string $originalUrl
*/
public function __construct(string $type, string $shortUrl, string $originalUrl)
{
$this->type = $type;
$this->shortUrl = $shortUrl;
$this->originalUrl = $originalUrl;
}
/**
* @return string
*/
public function getType(): string
{
return $this->type;
}
/**
* @return string
*/
public function getShortUrl(): string
{
return $this->shortUrl;
}
/**
* @return string
*/
public function getOriginalUrl(): string
{
return $this->originalUrl;
}
}
@@ -0,0 +1,59 @@
<?php
namespace App\Classes\Modules\HelpMenu\Processors;
use App\Models\QAUserAnswerSelected;
use App\Classes\Modules\HelpMenu\Services\FetchesHelpMenuUserAnswerSelected;
use App\Classes\Modules\HelpMenu\Services\ListsHelpMenuUserAnswerSelected;
class DeleteAnswerQAProcessor
{
/** @var FetchesHelpMenuUserAnswerSelected */
private $fetchesHelpMenuUserAnswerSelected;
/** @var ListsHelpMenuUserAnswerSelected */
private $listsHelpMenuUserAnswerSelected;
/**
* DeleteAnswerQAProcessor constructor.
* @param FetchesHelpMenuUserAnswerSelected $fetchesHelpMenuUserAnswerSelected
* @param ListsHelpMenuUserAnswerSelected $listsHelpMenuUserAnswerSelected
*/
public function __construct(FetchesHelpMenuUserAnswerSelected $fetchesHelpMenuUserAnswerSelected, ListsHelpMenuUserAnswerSelected $listsHelpMenuUserAnswerSelected)
{
$this->fetchesHelpMenuUserAnswerSelected = $fetchesHelpMenuUserAnswerSelected;
$this->listsHelpMenuUserAnswerSelected = $listsHelpMenuUserAnswerSelected;
}
/**
* @param int $userId
* @param int $questionId
* @param Request $request
* @return void
* @throws ResourceNotFoundException
*/
public function execute($userId, $questionId, $request){
if ($request->has('isPrevious')) {
//Get current and previous question's answer
try{
$selectedAnswer = $this->listsHelpMenuUserAnswerSelected->execute(['user_id' => $userId, 'question_id' => $questionId, 'order_by' => (object)['column' => 'id','DESC' => true]])[0];
} catch (\Exception $exception){
$selectedAnswer = null;
}
if($selectedAnswer)
{
$this->fetchesHelpMenuUserAnswerSelected->execute(['id' => $selectedAnswer['id']])->delete();
}
}
else{
//Delete all answer's belongs to the user
$currentQuestion = $request->question;
$isStart = $currentQuestion['is_start'];
if($isStart){
QAUserAnswerSelected::where('user_id', $userId)->delete();
}
}
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Classes\Modules\HelpMenu\Processors;
use App\Classes\Modules\HelpMenu\Services\FetchesHelpMenuQuestion;
use ErrorException;
use Illuminate\Http\Request;
class FetchFirstQuestionQAProcessor
{
/** @var FetchesHelpMenuQuestion */
private $fetchesHelpMenuQuestion;
/**
* FetchFirstQuestionQAProcessor constructor.
* @param FetchesHelpMenuQuestion $fetchesHelpMenuQuestion
*/
public function __construct(FetchesHelpMenuQuestion $fetchesHelpMenuQuestion)
{
$this->fetchesHelpMenuQuestion = $fetchesHelpMenuQuestion;
}
public function execute(Request $request){
try {
$query = $this->fetchesHelpMenuQuestion->execute(['questionnaire_set_id' => $request->route('set_id')]);
return $query;
} catch (\Exception $exception){
throw new ErrorException($exception->getMessage(), $exception->getCode());
}
}
}
@@ -0,0 +1,96 @@
<?php
namespace App\Classes\Modules\HelpMenu\Processors;
use App\Classes\Modules\HelpMenu\Services\FetchesHelpMenuQuestion;
use App\Classes\Modules\HelpMenu\Services\FetchesHelpMenuUserAnswerSelected;
use App\Classes\Modules\HelpMenu\Services\ListsHelpMenuUserAnswerSelected;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Classes\ValueObjects\Constants\QAType;
class FetchNextQuestionQAProcessor
{
/** @var FetchesHelpMenuQuestion */
private $fetchesHelpMenuQuestion;
/** @var FetchesHelpMenuUserAnswerSelected */
private $fetchesHelpMenuUserAnswerSelected;
/** @var ListsHelpMenuUserAnswerSelected */
private $listsHelpMenuUserAnswerSelected;
/**
* FetchNextQuestionQAProcessor constructor.
* @param FetchesHelpMenuQuestion $fetchesHelpMenuQuestion
* @param FetchesHelpMenuUserAnswerSelected $fetchesHelpMenuUserAnswerSelected
* @param ListsHelpMenuUserAnswerSelected $listsHelpMenuUserAnswerSelected
*/
public function __construct(FetchesHelpMenuQuestion $fetchesHelpMenuQuestion, FetchesHelpMenuUserAnswerSelected $fetchesHelpMenuUserAnswerSelected, ListsHelpMenuUserAnswerSelected $listsHelpMenuUserAnswerSelected)
{
$this->fetchesHelpMenuQuestion = $fetchesHelpMenuQuestion;
$this->fetchesHelpMenuUserAnswerSelected = $fetchesHelpMenuUserAnswerSelected;
$this->listsHelpMenuUserAnswerSelected = $listsHelpMenuUserAnswerSelected;
}
public function execute(Request $request){
$isEnd = 0;
$questionId = 0;
$nextQuestionNumber = 0;
$nextNestedQuestion = 0;
$nextMainQuestion= 0;
$questionnaireSetId = 0;
$currentQuestion = $request->question;
$questionType = QAType::DEFAULT;
$returnQuestion = null;
if ($currentQuestion && array_key_exists('id', $currentQuestion)) {
$questionId = $currentQuestion['id'];
$isEnd = $currentQuestion['is_end'];
$questionType = $currentQuestion['question_type'];
$nextNestedQuestion = $currentQuestion['next_nested_question'];
$nextMainQuestion = $currentQuestion['next_main_question'];
$questionnaireSetId = $currentQuestion['questionnaire_set_id'];
}
if ($request->has('answerObj')) {
$nextQuestionNumber = $request->answerObj['next_question_number'];
}
if ($request->has('isPrevious')) {
$userId = Auth::user()->id;
$previousAnswer = $this->listsHelpMenuUserAnswerSelected->execute(['user_id' => $userId, 'order_by' => (object)['column' => 'id','DESC' => true]])[0];
//Get previous question
$previousQuestion = $this->fetchesHelpMenuQuestion->execute(['questionnaire_set_id' => $questionnaireSetId, 'id' => $previousAnswer['question_id']]);
$returnQuestion = $previousQuestion;
}
else{
//Get next question
$nextQuestion = null;
$question_number = 0;
if($nextQuestionNumber != 0){
$question_number = $nextQuestionNumber;
}
else if($nextNestedQuestion != 0){
$question_number = $nextNestedQuestion;
}
else {
$question_number = $nextMainQuestion;
}
if($isEnd){
$returnQuestion = null;
}
else if($question_number != 0){
$nextQuestion = $this->fetchesHelpMenuQuestion->execute(['questionnaire_set_id' => $questionnaireSetId, 'question_number' => $question_number]);
$returnQuestion = $nextQuestion;
}
else if (array_key_exists('id', $request->input('question'))) {
$nextQuestion = $this->fetchesHelpMenuQuestion->execute(['questionnaire_set_id' => $questionnaireSetId, 'id_next' => $questionId, 'next_main_question' => null]);
$returnQuestion = $nextQuestion;
}
}
return $returnQuestion;
}
}
@@ -0,0 +1,65 @@
<?php
namespace App\Classes\Modules\HelpMenu\Processors;
use App\Models\QAUserAnswerSelected;
use App\Classes\Modules\HelpMenu\Services\FetchesHelpMenuUserAnswerSelected;
use App\Classes\Modules\Documents\Processors\UploadDocumentForHelpMenuProcessor;
class SaveAnswerProcessor
{
/** @var FetchesHelpMenuUserAnswerSelected */
private $fetchesHelpMenuUserAnswerSelected;
/** @var UploadDocumentForHelpMenuProcessor */
private $uploadDocumentForHelpMenuProcessor;
/**
* SaveAnswerProcessor constructor.
* @param FetchesHelpMenuUserAnswerSelected $fetchesHelpMenuUserAnswerSelected
* @param UploadDocumentForHelpMenuProcessor $uploadDocumentForHelpMenuProcessor
*/
public function __construct(FetchesHelpMenuUserAnswerSelected $fetchesHelpMenuUserAnswerSelected, UploadDocumentForHelpMenuProcessor $uploadDocumentForHelpMenuProcessor)
{
$this->fetchesHelpMenuUserAnswerSelected = $fetchesHelpMenuUserAnswerSelected;
$this->uploadDocumentForHelpMenuProcessor = $uploadDocumentForHelpMenuProcessor;
}
public function execute($userId, $sourceId, $questionId, $answerInText, $answerOptionId, $filesUpload, $reference = null){
$answer = null;
// try{
// // $answer = $this->fetchesHelpMenuUserAnswerSelected->execute(['user_id' => $userId, 'question_id' => $questionId, 'order_by' => ['column' => 'id','DESC' => 1]]);
// $answer = $this->fetchesHelpMenuUserAnswerSelected->execute(['user_id' => $userId, 'user_id' => $sourceId, 'question_id' => $questionId]);
// } catch (\Exception $exception){
// $answer = null;
// }
if(is_null($answer))
{
$answer = new QAUserAnswerSelected;
}
$answer->user_id = $userId;
$answer->source_id = $sourceId;
$answer->question_id = $questionId;
$answer->answer_option_id = intval($answerOptionId);
$answer->free_text_answer = $answerInText;
if($reference){
$answer->reference = $reference;
}
$answer->save();
if($filesUpload){
$result = $this->uploadDocumentForHelpMenuProcessor->execute($filesUpload, $answer);
$newData = array_map(function ($item) {
return [
'document_id' => $item->document_id,
'file_id' => $item->id,
];
}, $result);
$answer->free_text_answer = json_encode($newData);
$answer->save();
}
}
}
@@ -0,0 +1,70 @@
<?php
namespace App\Classes\Modules\HelpMenu\Processors;
use App\Classes\Modules\Accounts\Services\FetchesUser;
use App\Classes\Modules\HelpMenu\Services\FetchesQAUserSource;
use App\Classes\Modules\HelpMenu\Services\CreatesQAUserSource;
use App\Classes\ValueObjects\Constants\QASystemSourceType;
use App\Classes\Exceptions\ResourceNotFoundException;
use App\Classes\Modules\HelpMenu\DataTransferObjects\QAUserSourceObject;
class UserSourceForQAProcessor
{
/** @var FetchesUser */
private $fetchesUser;
/** @var FetchesQAUserSource */
private $fetchesQAUserSource;
/** @var CreatesQAUserSource */
private $createsQAUserSource;
/**
* UserSourceForQAProcessor constructor.
* @param FetchesUser $fetchesUser
* @param FetchesQAUserSource $fetchesQAUserSource
* @param CreatesQAUserSource $createsQAUserSource
*/
public function __construct(FetchesUser $fetchesUser, FetchesQAUserSource $fetchesQAUserSource, CreatesQAUserSource $createsQAUserSource)
{
$this->fetchesUser = $fetchesUser;
$this->fetchesQAUserSource = $fetchesQAUserSource;
$this->createsQAUserSource = $createsQAUserSource;
}
public function execute($system, $customerMarking, $email){
$result = [];
$isFound = false;
if((int)$system === QASystemSourceType::IZYIM){
try{
$query = $this->fetchesUser->execute(['email' => $email]);
$result['userId'] = $query->id;
$result['sourceId'] = 0;
$isFound = true;
} catch (ResourceNotFoundException $exception){
$isFound = false;
}
}
if(!$isFound){
try{
$query = $this->fetchesQAUserSource->execute(['email' => $email]);
$result['userId'] = 0;
$result['sourceId'] = $query->id;
} catch (ResourceNotFoundException $exception){
$result['sourceId'] = 0;
}
if($result['sourceId'] === 0){
$new_object = new QAUserSourceObject($system, $customerMarking, $email);
$query = $this->createsQAUserSource->execute($new_object);
$result['userId'] = 0;
$result['sourceId'] = $query->id;
}
}
return $result;
}
}
@@ -0,0 +1,25 @@
<?php
namespace App\Classes\Modules\HelpMenu\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Classes\Modules\HelpMenu\DataTransferObjects\QAUserSourceObject;
use App\Models\QAUserSource;
class CreatesQAUserSource extends AbstractUpdateRecord
{
/**
* @param QAUserSourceObject $object
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(QAUserSourceObject $object) {
$model = new QAUserSource();
$model->system = $object->getSystem();
$model->marking = $object->getMarking();
$model->email = $object->getEmail();
return $this->handler($model);
}
}
@@ -0,0 +1,25 @@
<?php
namespace App\Classes\Modules\HelpMenu\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Classes\Modules\HelpMenu\DataTransferObjects\UrlObject;
use App\Models\Url;
class CreatesUrl extends AbstractUpdateRecord
{
/**
* @param UrlObject $object
* @return \Illuminate\Database\Eloquent\Model
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(UrlObject $object) {
$model = new Url();
$model->type = $object->getType();
$model->short_url = $object->getShortUrl();
$model->original_url = $object->getOriginalUrl();
return $this->handler($model);
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Classes\Modules\HelpMenu\Services;
use App\Classes\General\Eloquent\AbstractFetchRecord;
use Illuminate\Database\Eloquent\Builder;
use App\Models\QAQuestions;
class FetchesHelpMenuQuestion extends AbstractFetchRecord
{
/** @var QAQuestions */
private $repository;
/**
* FetchesHelpMenuQuestion constructor.
* @param QAQuestions $repository
*/
public function __construct(QAQuestions $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
public function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Classes\Modules\HelpMenu\Services;
use App\Classes\General\Eloquent\AbstractFetchRecord;
use Illuminate\Database\Eloquent\Builder;
use App\Models\QAUserAnswerSelected;
class FetchesHelpMenuUserAnswerSelected extends AbstractFetchRecord
{
/** @var QAUserAnswerSelected */
private $repository;
/**
* FetchesHelpMenuUserAnswerSelected constructor.
* @param QAUserAnswerSelected $repository
*/
public function __construct(QAUserAnswerSelected $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
public function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -0,0 +1,33 @@
<?php
namespace App\Classes\Modules\HelpMenu\Services;
use App\Classes\General\Eloquent\AbstractFetchRecord;
use Illuminate\Database\Eloquent\Builder;
use App\Models\QAUserSource;
class FetchesQAUserSource extends AbstractFetchRecord
{
/** @var QAUserSource */
private $repository;
/**
* FetchesQAUserSource constructor.
* @param QAUserSource $repository
*/
public function __construct(QAUserSource $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
public function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Classes\Modules\HelpMenu\Services;
use App\Classes\General\Eloquent\AbstractFetchRecord;
use App\Models\Url;
use Illuminate\Database\Eloquent\Builder;
class FetchesUrl extends AbstractFetchRecord
{
/** @var Url */
private $repository;
/**
* FetchesUrl constructor.
* @param Url $repository
*/
public function __construct(Url $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
public function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Classes\Modules\HelpMenu\Services;
use App\Classes\General\Eloquent\AbstractListRecord;
use Illuminate\Database\Eloquent\Builder;
use App\Models\QAQuestions;
class ListsHelpMenuQuestions extends AbstractListRecord
{
/** @var QAQuestions */
private $repository;
/**
* ListsHelpMenuQuestions constructor.
* @param QAQuestions $repository
*/
public function __construct(QAQuestions $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
public function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -0,0 +1,32 @@
<?php
namespace App\Classes\Modules\HelpMenu\Services;
use App\Classes\General\Eloquent\AbstractListRecord;
use Illuminate\Database\Eloquent\Builder;
use App\Models\QAUserAnswerSelected;
class ListsHelpMenuUserAnswerSelected extends AbstractListRecord
{
/** @var QAUserAnswerSelected */
private $repository;
/**
* ListsHelpMenuUserAnswerSelected constructor.
* @param QAUserAnswerSelected $repository
*/
public function __construct(QAUserAnswerSelected $repository)
{
$this->repository = $repository;
}
/**
* @return Builder
*/
public function getRepository(): Builder
{
return $this->repository->newQuery();
}
}
@@ -0,0 +1,38 @@
<?php
namespace App\Classes\Modules\HelpMenu\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
class CanFetchHelpMenuQuestion extends AbstractRule
{
/**
* @return bool
*/
protected function authorized(): bool
{
// TODO Set Authorization rules
return true;
}
/**
* @param $object
* @return bool
*/
protected function validators($object): bool
{
return true;
}
/**
* @param $object
* @return bool
*/
protected function criteria($object): bool
{
return true;
}
}
@@ -0,0 +1,43 @@
<?php
namespace App\Classes\Modules\HelpMenu\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\ValueObjects\Constants\RoleTypes;
class CanGenerateFeedbackUrl extends AbstractRule
{
/**
* @return bool
*/
protected function authorized(): bool
{
$roleToCheck = Auth()->user()->type;
if (in_array($roleToCheck, RoleTypes::ADMIN_ROLES)) {
return true;
} else {
return false;
}
}
/**
* @param $object
* @return bool
*/
protected function validators($object): bool
{
return true;
}
/**
* @param $object
* @return bool
*/
protected function criteria($object): bool
{
return true;
}
}
@@ -0,0 +1,45 @@
<?php
namespace App\Classes\Modules\HelpMenu\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\ValueObjects\Constants\RoleTypes;
class CanListHelpMenuQuestions extends AbstractRule
{
/**
* @return bool
*/
protected function authorized(): bool
{
$roleToCheck = Auth()->user()->type;
if (in_array($roleToCheck, RoleTypes::ADMIN_ROLES)) {
return true;
} else {
return false;
}
}
/**
* @param $object
* @return bool
*/
protected function validators($object): bool
{
return true;
}
/**
* @param $object
* @return bool
*/
protected function criteria($object): bool
{
return true;
}
}
@@ -119,13 +119,13 @@ class TransactionToPerfexCRMV2Processor
}
private function definePaymentTasks(Transaction $model): array //cief todo: to comfirm what tasks need to be created
private function definePaymentTasks(Transaction $model): array //cief todo: to comfirm what tasks need to be created at crm
{
$tasks = [];
return $tasks;
}
private function defineTasks_handleApprovedStatus_handlePaymentApprovedStatus(): array //cief todo: to comfirm what tasks need to be created
private function defineTasks_handleApprovedStatus_handlePaymentApprovedStatus(): array //cief todo: to comfirm what tasks need to be created at crm
{
$tasks = [];
// $tasks = [
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class ConvertsPerfexCRMLeadToCustomer
@@ -27,8 +28,13 @@ class ConvertsPerfexCRMLeadToCustomer
Log::error('ConvertsPerfexCRMLeadToCustomer: '.$response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), $email, $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class CreatesPerfexCRMCustomer
@@ -30,8 +31,13 @@ class CreatesPerfexCRMCustomer
Log::error('CreatesPerfexCRMCustomer: '.$response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), $companyName, $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
}
@@ -5,6 +5,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use App\Classes\Modules\PerfexCRM\DataTransferObjects\CustomerContactObject;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class CreatesPerfexCRMCustomerContact
@@ -37,8 +38,13 @@ class CreatesPerfexCRMCustomerContact
Log::error('CreatesPerfexCRMCustomerContact: '.$response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class CreatesPerfexCRMCustomerProject
@@ -36,8 +37,13 @@ class CreatesPerfexCRMCustomerProject
Log::error('CreatesPerfexCRMCustomerProject: '.$response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
use App\Classes\Modules\PerfexCRM\DataTransferObjects\InvoicePerfexCRMObject;
@@ -56,8 +57,13 @@ class CreatesPerfexCRMInvoice
Log::error('CreatesPerfexCRMInvoice: '.$response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
use App\Classes\Modules\PerfexCRM\DataTransferObjects\InvoicePaymentPerfexCRMObject;
@@ -36,8 +37,13 @@ class CreatesPerfexCRMInvoicePayment
Log::error('CreatesPerfexCRMInvoicePayment: '.$response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
use App\Classes\Modules\PerfexCRM\DataTransferObjects\CreateLeadPerfexCRMObject;
@@ -43,8 +44,13 @@ class CreatesPerfexCRMLead
Log::error('CreatesPerfexCRMLead: '.$response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server ' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class CreatesPerfexCRMMilestone
@@ -39,8 +40,13 @@ class CreatesPerfexCRMMilestone
Log::error('CreatesPerfexCRMMilestone: '.$response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
}
@@ -0,0 +1,52 @@
<?php
namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class CreatesPerfexCRMSupportTicket
{
/**
* @param string $subject
* @param string $department
* @param int $contactid
* @param int $userid
* @return null|object
* @throws MalformedRequestException
*/
public function execute(string $subject, string $department, int $contactid, int $userid) {
try{
$data = [
'subject' => $subject,
'department' => $department,
'contactid' => $contactid,
'userid' => $userid,
];
$response = Http::asForm()->withHeaders([
'authtoken' => config('perfexcrm.api_key')])
->post(config('perfexcrm.base_url').'/api/tickets',$data);
if($response->successful()){
$data = $response->json();
return (object) $data;
}else{
Log::error($response);
return null;
}
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
$error = 'Support Ticket creation failed';
Log::error($error. ": ". $exception->getMessage());
Log::error('Payload: '.json_encode($data));
throw new MalformedRequestException($error);
}
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
use App\Classes\ValueObjects\Constants\PerfexCRMCustomFields;
use App\Classes\Modules\PerfexCRM\DataTransferObjects\CreateTaskPerfexCRMObject;
@@ -60,8 +61,13 @@ class CreatesPerfexCRMTask
Log::error('CreatesPerfexCRMTask: '.$response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class FetchesPerfexCRMCustomer
@@ -27,8 +28,15 @@ class FetchesPerfexCRMCustomer
Log::error('FetchesPerfexCRMCustomer: '.$response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), $email, $exception->getTraceAsString());
}
catch(\Exception $exception){
$error = 'Unable to get correct response from Perfex CRM server: ' . $exception->getMessage();
Log::error($error);
throw new MalformedRequestException($error);
}
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class FetchesPerfexCRMInvoice
@@ -29,7 +30,12 @@ class FetchesPerfexCRMInvoice
Log::error('FetchesPerfexCRMInvoice: '.$response);
return null;
}
}catch(\Exception $exception){
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class FetchesPerfexCRMLead
@@ -27,7 +28,12 @@ class FetchesPerfexCRMLead
Log::error('FetchesPerfexCRMLead: '.$response);
return null;
}
}catch(\Exception $exception){
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), $email, $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class FetchesPerfexCRMMilestone
@@ -33,8 +34,13 @@ class FetchesPerfexCRMMilestone
Log::error('FetchesPerfexCRMMilestone: '.$response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class FetchesPerfexCRMProject
@@ -33,8 +34,13 @@ class FetchesPerfexCRMProject
Log::error('FetchesPerfexCRMProject: '.$response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
use App\Classes\General\Helper;
@@ -47,8 +48,13 @@ class FetchesPerfexCRMTask
Helper::debugLogger($response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
use App\Classes\ValueObjects\Constants\PerfexCRMCustomFields;
use App\Classes\General\Helper;
@@ -41,8 +42,13 @@ class UpdatesPerfexCRMCustomer
// Helper::debugLogger($response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class UpdatesPerfexCRMInvoice
@@ -63,7 +64,12 @@ class UpdatesPerfexCRMInvoice
Log::error('UpdatesPerfexCRMInvoice: '.$response);
return null;
}
}catch(\Exception $exception){
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
use App\Classes\ValueObjects\Constants\PerfexCRMCustomFields;
@@ -44,7 +45,12 @@ class UpdatesPerfexCRMLead
Log::error('UpdatesPerfexCRMLead: '.$response);
return null;
}
}catch(\Exception $exception){
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class UpdatesPerfexCRMProject
@@ -36,7 +37,12 @@ class UpdatesPerfexCRMProject
Log::error('UpdatesPerfexCRMProject: '.$response);
return null;
}
}catch(\Exception $exception){
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
@@ -4,6 +4,7 @@ namespace App\Classes\Modules\PerfexCRM\Services;
use Illuminate\Support\Facades\Http;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Exceptions\ConnectionErrorException;
use Illuminate\Support\Facades\Log;
class UpdatesPerfexCRMTask
@@ -41,8 +42,13 @@ class UpdatesPerfexCRMTask
Log::error('UpdatesPerfexCRMTask: '.$response);
return null;
}
}catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server' . $exception->getMessage());
}
catch(\Illuminate\Http\Client\ConnectionException $exception){
$error = 'Failed to connect to CRM';
throw new ConnectionErrorException($error, $exception->getMessage(), "", $exception->getTraceAsString());
}
catch(\Exception $exception){
throw new MalformedRequestException('Unable to get correct response from Perfex CRM server: ' . $exception->getMessage());
}
}
}
@@ -47,7 +47,7 @@ class CreatePaymentTransactionLogic extends AbstractControllerLogic
$payment_transaction = $this->createPaymentTransactionProcessor->execute($invoice_transaction, $payment_method , $request->input('bank_code'));
//cief todo: at exchange there is a transition step
//cief todo: at exchange there is a transition step - starts
// if(PaymentMethodType::PAYMENT_METHODS[$request->input('payment_method')] == PaymentMethodType::PAYMENT_GATEWAY){
// $this->updatesTransactionStatus->execute($transaction, ApprovalStatus::PENDING_VERIFICATION);
// }
@@ -59,7 +59,7 @@ class CreatePaymentTransactionLogic extends AbstractControllerLogic
//To use
//ApprovalStatus::PENDING_VERIFICATION;
//use this to trigger $this->transactionToPerfexCRMV2Processor->execute > defineTasks > defineTasks_handlePendingVerificationStatus > definePaymentTasks
//cief todo: at exchange there is a transition step - ends
return $this->resourceResponse(new TransactionResource($payment_transaction));
}
@@ -0,0 +1,25 @@
<?php
namespace App\Classes\ValueObjects\Constants;
final class QASystemSourceType {
public const IZYIM = 1;
public const EXCHANGE = 2;
public const LITE = 3;
public static function getText($value) {
switch ($value) {
case self::IZYIM:
return 'IZYIM';
case self::EXCHANGE:
return 'Exchange';
case self::LITE:
return 'Lite';
default:
return 'Unknown';
}
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Classes\ValueObjects\Constants;
final class QAType {
public const DEFAULT = 0;
public const MULTIPLE_CHOICES = 1;
public const FREE_TEXT = 2;
public const DOCUMENT_UPLOAD = 3;
public const ANSWER = 4;
public const TICKET_CRM = 5;
public const RATING_5_STARS = 6;
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\HelpMenu;
use App\Classes\Modules\HelpMenu\ControllersLogic\FetchQuestionQALogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class FetchQuestionQAController
{
/**
* @param Request $request
* @param FetchQuestionQALogic $logic
* @return JsonResponse
*/
public function fetch(Request $request, FetchQuestionQALogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\HelpMenu;
use App\Classes\Modules\HelpMenu\ControllersLogic\GenerateFeedbackUrlLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class GenerateFeedbackUrlController
{
/**
* @param Request $request
* @param GenerateFeedbackUrlLogic $logic
* @return JsonResponse
*/
public function generate(Request $request, GenerateFeedbackUrlLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\HelpMenu;
use App\Classes\Modules\HelpMenu\ControllersLogic\ListQuestionsAnswersQALogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListQuestionsAnswersQAController
{
/**
* @param Request $request
* @param ListQuestionsAnswersQALogic $logic
* @return JsonResponse
*/
public function list(Request $request, ListQuestionsAnswersQALogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Http\Controllers\HelpMenu;
use App\Classes\Modules\HelpMenu\ControllersLogic\ListQuestionsQALogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListQuestionsQAController
{
/**
* @param Request $request
* @param ListQuestionsQALogic $logic
* @return JsonResponse
*/
public function list(Request $request, ListQuestionsQALogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Http\Controllers\HelpMenu;
use App\Classes\Modules\HelpMenu\ControllersLogic\SubmitQAQuestionsLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class SubmitQAQuestionsController
{
/**
* @param Request $request
* @param SubmitQAQuestionsLogic $logic
* @return JsonResponse
*/
public function submit(Request $request, SubmitQAQuestionsLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Http\Controllers\HelpMenu;
use App\Classes\Modules\HelpMenu\ControllersLogic\UpdateNextQuestionQALogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class UpdateNextQuestionQAController
{
/**
* @param Request $request
* @param FetchQAQuestionListLogic $logic
* @return JsonResponse
*/
public function fetch(Request $request, UpdateNextQuestionQALogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,26 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class HelpMenuAnswerOptionsResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'display_text' => $this->display_text,
'value' => $this->value,
'order' => $this->order,
'question_number' => $this->question_number,
'next_question_number' => $this->next_question_number,
];
}
}
@@ -0,0 +1,53 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use App\Models\QAQuestions;
use App\Models\QAAnswerOptions;
use App\Models\QAUserAnswerSelected;
class HelpMenuQuestionResource extends JsonResource
{
/** @var integer */
private $userId;
/** @var QAQuestions*/
private $question;
public function __construct($question, $userId) {
$this->question = $question;
$this->userId = $userId;
}
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
if($this->question){
$q = (object)$this->question;
return [
'id' => $q->id,
'question_number' => $q->question_number,
'question_text' => $q->question_text,
'question_type' => $q->question_type,
'question_answers' => HelpMenuAnswerOptionsResource::collection(QAAnswerOptions::where('question_number', $q->question_number)->where('questionnaire_set_id', $q->questionnaire_set_id)->get()),
'questionnaire_set_id' => $q->questionnaire_set_id,
'next_nested_question' => $q->next_nested_question,
'next_main_question' => $q->next_main_question,
'is_start' => $q->is_start,
'is_end' => $q->is_end,
'end_text' => $q->end_text,
'order' => $q->order,
'answer' => QAUserAnswerSelected::where('question_id', $q->id)->where('user_id', $this->userId)->first(),
'questionnaire_answers' => $q->is_end ? HelpMenuQuestionnaireAnswersResource::collection(QAUserAnswerSelected::where('user_id', $this->userId)->get()) : null,
];
}
else{
return [];
}
}
}
@@ -0,0 +1,24 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use App\Models\QAQuestions;
class HelpMenuQuestionnaireAnswersResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$question = QAQuestions::where('id', $this->question_id)->first();
return [
'question_text' => $question ? $question->question_text : null,
'free_text_answer' => $this->free_text_answer
];
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class HelpMenuQuestionnaireSetsResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'name' => $this->name,
'description' => $this->description,
'group' => $this->group,
];
}
}
@@ -0,0 +1,41 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use App\Classes\ValueObjects\Constants\QASystemSourceType;
use App\Models\QAQuestions;
use Carbon\Carbon;
class HelpMenuQuestionsAnswersResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$question = QAQuestions::where('id', $this->question_id)->first();
$source = new HelpMenuUserSourceResource($this->userSource);
$user = $this->source_id === 0 ? new UserResource($this->user) : null;
$user_marking = '';
if($user){
$companyModule = $user->companyModule()->first();
$user_marking = $companyModule ? $companyModule->inviters()->withPivot('invitee_reference')->first()->pivot->invitee_reference : "";
}
return [
'question_id' => $this->question_id,
'questionnaire' => new HelpMenuQuestionnaireSetsResource($this->question->questionnaire),
'question_text' => $question ? $question->question_text : null,
'free_text_answer' => $this->free_text_answer,
'source_system' => $user ? QASystemSourceType::getText(QASystemSourceType::IZYIM) : QASystemSourceType::getText($source->system),
'source_marking' => $user ? $user_marking : $source->marking,
'source_email' => $user ? $user->email : $source->email,
'created_at' => Carbon::parse($this->created_at)->format('d-m-Y'),
];
}
}
@@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class HelpMenuUserSourceResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'system' => $this->system,
'email' => $this->email,
'marking' => $this->marking,
];
}
}
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace App\Models;
class QAAnswerOptions extends AbstractModel
{
protected $table = 'qa_answer_options';
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\HasMany;
class QAQuestionnaireSet extends AbstractModel
{
protected $table = 'qa_questionnaire_sets';
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class QAQuestions extends AbstractModel
{
protected $table = 'qa_questions';
/**
* @return BelongsTo
*/
public function questionnaire(): BelongsTo
{
return $this->BelongsTo(QAQuestionnaireSet::class, 'questionnaire_set_id', 'id');
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
namespace App\Models;
use App\Classes\General\Interfaces\Documentable;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphMany;
/**
* Class Contact
* @package App\Models
*/
class QAUserAnswerSelected extends AbstractModel implements Documentable
{
protected $table = 'qa_user_answer_selected';
/**
* @return MorphMany
*/
public function documents(): morphMany
{
return $this->morphMany(Document::class, 'owner');
}
/**
* @return BelongsTo
*/
public function userSource(): BelongsTo
{
return $this->BelongsTo(QAUserSource::class, 'source_id', 'id');
}
/**
* @return BelongsTo
*/
public function user(): BelongsTo
{
return $this->BelongsTo(User::class, 'user_id', 'id');
}
/**
* @return BelongsTo
*/
public function question(): BelongsTo
{
return $this->BelongsTo(QAQuestions::class, 'question_id', 'id');
}
}
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace App\Models;
class QAUserSource extends AbstractModel
{
protected $table = 'qa_user_source';
}
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace App\Models;
class Url extends AbstractModel
{
protected $table = 'urls';
}
@@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateQAQuestionnaireSetsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('qa_questionnaire_sets', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('description')->nullable();
$table->string('group')->nullable();
$table->unsignedBigInteger('order')->default(0);
$table->unsignedBigInteger('next_set')->nullable();
$table->unsignedBigInteger('version')->default(1);
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('qa_questionnaire_sets');
}
}
@@ -0,0 +1,45 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateQAQuestionsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('qa_questions', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('question_number');
$table->text('question_text');
$table->unsignedBigInteger('questionnaire_set_id');
$table->unsignedBigInteger('next_nested_question')->nullable();
$table->unsignedBigInteger('next_main_question')->nullable();
$table->unsignedBigInteger('question_type');
$table->tinyInteger('is_start');
$table->tinyInteger('is_end');
$table->string('end_text')->nullable();
$table->unsignedBigInteger('order')->default(0);
$table->timestamps();
$table->softDeletes();
$table->foreign('questionnaire_set_id')->references('id')->on('qa_questionnaire_sets');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('qa_questions');
}
}
@@ -0,0 +1,41 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateQAAnswerOptionsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('qa_answer_options', function (Blueprint $table) {
$table->id();
$table->text('display_text');
$table->string('value');
$table->unsignedBigInteger('order')->default(0);
$table->unsignedBigInteger('question_number');
$table->unsignedBigInteger('next_question_number')->nullable();
$table->unsignedBigInteger('questionnaire_set_id');
$table->timestamps();
$table->softDeletes();
$table->foreign('questionnaire_set_id')->references('id')->on('qa_questionnaire_sets');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('qa_answer_options');
}
}
@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateQaUserSourceTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('qa_user_source', function (Blueprint $table) {
$table->id();
$table->string('system');
$table->string('email');
$table->string('marking');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('qa_user_source');
}
}
@@ -0,0 +1,43 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateQAUserAnswerSelectedTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('qa_user_answer_selected', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id')->default(0);
$table->unsignedBigInteger('source_id')->default(0);
$table->unsignedBigInteger('question_id');
$table->unsignedBigInteger('answer_option_id')->default(0);
$table->string('free_text_answer')->nullable();
$table->string('reference')->nullable();
$table->timestamps();
$table->softDeletes();
$table->foreign('question_id')->references('id')->on('qa_questions');
// $table->foreign('answer_option_id')->references('id')->on('qa_answer_options');
// $table->foreign('user_id')->references('id')->on('users');
// $table->foreign('source_id')->references('id')->on('qa_user_source');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('qa_user_answer_selected');
}
}
@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUrlsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('urls', function (Blueprint $table) {
$table->id();
$table->string('type');
$table->string('short_url');
$table->text('original_url');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('urls');
}
}
+7
View File
@@ -21,5 +21,12 @@ class DatabaseSeeder extends Seeder
$this->call(SegmentConstantsTableSeeder::class);
$this->call(DummyDataSeeder::class);
// $this->call(QAQuestionsDemoSeeder::class); //DEMO POC
// $this->call(QAAnswerOptionsDemoSeeder::class); //DEMO POC
// $this->call(QAQuestionsSeeder::class);
// $this->call(QAAnswerOptionsSeeder::class);
}
}
@@ -0,0 +1,193 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\QAAnswerOptions;
class QAAnswerOptionsDemoSeeder extends Seeder
{
public function run()
{
//Set 1
// Option 1 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Billing";
$answerOption->value = "Billing";
$answerOption->question_number = 10;
$answerOption->next_question_number = 100;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 2 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Shipping";
$answerOption->value = "Shipping";
$answerOption->question_number = 10;
$answerOption->next_question_number = 100;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 3 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Returns";
$answerOption->value = "Returns";
$answerOption->question_number = 10;
$answerOption->next_question_number = 100;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 4 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Product Information";
$answerOption->value = "Product Information";
$answerOption->question_number = 10;
$answerOption->next_question_number = 100;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 5 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Technical Support";
$answerOption->value = "Technical Support";
$answerOption->question_number = 10;
$answerOption->next_question_number = 100;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 6 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Shipping Fee Calculation";
$answerOption->value = "Shipping Fee Calculation";
$answerOption->question_number = 10;
$answerOption->next_question_number = 600;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 7 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Error-in Measurements";
$answerOption->value = "Error-in Measurements";
$answerOption->question_number = 10;
$answerOption->next_question_number = 700;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 8 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Contact Us";
$answerOption->value = "Contact Us";
$answerOption->question_number = 10;
$answerOption->next_question_number = 800;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 1 for Question 20
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Option 1 for Question 20";
$answerOption->value = "Option 1 for Question 20";
$answerOption->question_number = 20;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 2 for Question 20
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Option 2 for Question 20";
$answerOption->value = "Option 2 for Question 20";
$answerOption->question_number = 20;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 1 for Question 100
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Option 1 for Question 100";
$answerOption->value = "Option 1 for Question 100";
$answerOption->question_number = 100;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 2 for Question 100
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Option 2 for Question 100";
$answerOption->value = "Option 2 for Question 100";
$answerOption->question_number = 100;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 1 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Option 1 for Question 30";
$answerOption->value = "Option 1 for Question 30";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 2 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Option 2 for Question 30";
$answerOption->value = "Option 2 for Question 30";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 3 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Option 3 for Question 30";
$answerOption->value = "Option 3 for Question 30";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 1 for Question 300
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Option 1 for Question 300";
$answerOption->value = "Option 1 for Question 300";
$answerOption->question_number = 300;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 2 for Question 300
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Option 2 for Question 300";
$answerOption->value = "Option 2 for Question 300";
$answerOption->question_number = 300;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 3 for Question 300
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Option 3 for Question 300";
$answerOption->value = "Option 3 for Question 300";
$answerOption->question_number = 300;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 1 for Question 600
$answerOption = new QAAnswerOptions;
$answerOption->display_text = '<h1>Et harum accusamus eum quis dolorum? </h1><p>Lorem ipsum dolor sit amet. Est corporis voluptas et repudiandae libero <em>Aut quis</em>! Est aperiam voluptatum eum quidem rerumnam deserunt sit internos possimus non dolore voluptate. Vel explicabo aliquam <strong>Sit sunt ut maxime voluptatibus non vero libero ad ratione dolore</strong>. </p><h2>Ea incidunt dolor in obcaecati harum ut dignissimos facilis! </h2><p>Et adipisci illo et laborum internos <strong>Nam aperiam est ipsa nisi non quia architecto ut itaque autem</strong>. Eos maiores sunt <em>Et voluptas aut expedita quidem aut odio repellendus eum neque voluptate</em> et iusto nisi vel consequatur quos. Sit doloribus omnis in minima illoQui soluta est omnis quasi vel officia reiciendis qui aliquid quis! Sed odit esse aut sint laborumEa internos et magni amet sed dolores omnis hic totam temporibus ut quia numquam. </p><ul><li>Est soluta praesentium ut vero obcaecati! </li><li>Sit nobis facere in porro rerum et quidem deserunt qui inventore odit. </li></ul><h3>Et laborum quaerat vel animi ipsum. </h3><p>Aut quos libero <a href="https://www.loremipzum.com" target="_blank">Et explicabo qui enim libero id rerum ipsa</a>. Est quod tempora est soluta enimaut quasi aut eligendi fugit et fugit Quis. </p>
';
$answerOption->value = "Answer";
$answerOption->question_number = 600;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Set 2
// Option 1 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Yes";
$answerOption->value = "Yes";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Option 2 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "No";
$answerOption->value = "No";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
}
}
+356
View File
@@ -0,0 +1,356 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\QAAnswerOptions;
class QAAnswerOptionsSeeder extends Seeder
{
public function run()
{
// Set 1
// Option 1 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "1 (Very Dissatisfied)";
$answerOption->value = "1";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 2 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "2 (Dissatisfied)";
$answerOption->value = "2";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 3 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "3 (Neutral)";
$answerOption->value = "3";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 4 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "4 (Satisfied)";
$answerOption->value = "4";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 5 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "5 (Very Satisfied)";
$answerOption->value = "5";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Set 1
// Option 1 for Question 20
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Yes";
$answerOption->value = "Yes";
$answerOption->question_number = 20;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 2 for Question 20
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Partially";
$answerOption->value = "Partially";
$answerOption->question_number = 20;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 3 for Question 20
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "No";
$answerOption->value = "No";
$answerOption->question_number = 20;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Set 1
// Option 1 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Very Clear";
$answerOption->value = "Very Clear";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 2 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Clear";
$answerOption->value = "Clear";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 3 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Neutral";
$answerOption->value = "Neutral";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 4 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Unclear";
$answerOption->value = "Unclear";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 5 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Very Unclear";
$answerOption->value = "Very Unclear";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Set 2
// Option 1 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Yes";
$answerOption->value = "Yes";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 2;
$answerOption->save();
// Option 2 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Somewhat";
$answerOption->value = "Somewhat";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 2;
$answerOption->save();
// Option 3 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "No";
$answerOption->value = "No";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 2;
$answerOption->save();
// Set 2
// Option 1 for Question 20
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Exceeded Expectations";
$answerOption->value = "Exceeded Expectations";
$answerOption->question_number = 20;
$answerOption->questionnaire_set_id = 2;
$answerOption->save();
// Option 2 for Question 20
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Met Expectations";
$answerOption->value = "Met Expectations";
$answerOption->question_number = 20;
$answerOption->questionnaire_set_id = 2;
$answerOption->save();
// Option 3 for Question 20
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Below Expectations";
$answerOption->value = "Below Expectations";
$answerOption->question_number = 20;
$answerOption->questionnaire_set_id = 2;
$answerOption->save();
// Set 2
// Option 1 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "1 (Very Dissatisfied)";
$answerOption->value = "1";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 2;
$answerOption->save();
// Option 2 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "2 (Dissatisfied)";
$answerOption->value = "2";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 2;
$answerOption->save();
// Option 3 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "3 (Neutral)";
$answerOption->value = "3";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 2;
$answerOption->save();
// Option 4 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "4 (Satisfied)";
$answerOption->value = "4";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 2;
$answerOption->save();
// Option 5 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "5 (Very Satisfied)";
$answerOption->value = "5";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 2;
$answerOption->save();
// Set 3
// Option 1 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Immediately";
$answerOption->value = "Immediately";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Option 2 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Within a few hours";
$answerOption->value = "Within a few hours";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Option 3 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Within a day";
$answerOption->value = "Within a day";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Option 4 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "More than a day";
$answerOption->value = "More than a day";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Option 5 for Question 10
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Never received a response";
$answerOption->value = "Never received a response";
$answerOption->question_number = 10;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Set 3
// Option 1 for Question 20
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Very Clear";
$answerOption->value = "Very Clear";
$answerOption->question_number = 20;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Option 2 for Question 20
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Clear";
$answerOption->value = "Clear";
$answerOption->question_number = 20;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Option 3 for Question 20
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Neutral";
$answerOption->value = "Neutral";
$answerOption->question_number = 20;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Option 4 for Question 20
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Unclear";
$answerOption->value = "Unclear";
$answerOption->question_number = 20;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Option 5 for Question 20
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Very Unclear";
$answerOption->value = "Very Unclear";
$answerOption->question_number = 20;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Set 3
// Option 1 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Very Likely";
$answerOption->value = "Very Likely";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Option 2 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Likely";
$answerOption->value = "Likely";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Option 3 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Neutral";
$answerOption->value = "Neutral";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Option 4 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Unlikely";
$answerOption->value = "Unlikely";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
// Option 5 for Question 30
$answerOption = new QAAnswerOptions;
$answerOption->display_text = "Very Unlikely";
$answerOption->value = "Very Unlikely";
$answerOption->question_number = 30;
$answerOption->questionnaire_set_id = 3;
$answerOption->save();
}
}
+247
View File
@@ -0,0 +1,247 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\QAQuestionnaireSet;
use App\Models\QAQuestions;
use App\Classes\ValueObjects\Constants\QAType;
class QAQuestionsDemoSeeder extends Seeder
{
public function run()
{
$questionnaireSets = [
[
'name' => 'Set 1',
'description' => 'This is set 1 questions',
],
[
'name' => 'Set 2',
'description' => 'Customer Service Satisfaction Questions',
],
[
'name' => 'Set 3',
'description' => 'Survey Before conservation with BD ends',
],
[
'name' => 'Set 4',
'description' => 'After First Order',
],
];
foreach ($questionnaireSets as $set) {
$questionnaireSet = QAQuestionnaireSet::create([
'name' => $set['name'],
'description' => $set['description'],
]);
$questions = [];
switch ($set['name']) {
case 'Set 1':
$questions = [
[
'question_number' => 10,
'question_text' => 'Please select one',
'question_type' => QAType::MULTIPLE_CHOICES,
'is_start' => true,
'is_end' => false,
],
[
'question_number' => 20,
'question_text' => 'Question text for question number 20?',
'question_type' => QAType::MULTIPLE_CHOICES,
'is_start' => false,
'is_end' => false,
],
[
'question_number' => 30,
'question_text' => 'Question text for question number 30?',
'question_type' => QAType::MULTIPLE_CHOICES,
'next_nested_question' => 300,
'is_start' => false,
'is_end' => false,
],
[
'question_number' => 40,
'question_text' => 'What is your name?',
'question_type' => QAType::FREE_TEXT,
'is_start' => false,
'is_end' => false,
],
[
'question_number' => 50,
'question_text' => 'The End',
'question_type' => QAType::ANSWER,
'is_start' => false,
'is_end' => true,
],
[
'question_number' => 60,
'question_text' => 'We have received your request and will response as soon as possible.',
'question_type' => QAType::TICKET_CRM,
'is_start' => false,
'is_end' => true,
],
[
'question_number' => 100,
'question_text' => 'Question text for question number 100?',
'question_type' => QAType::MULTIPLE_CHOICES,
'next_nested_question' => 110, //200 //3 digits - first level
'next_main_question' => 20,
'is_start' => false,
'is_end' => false,
],
[
'question_number' => 110,
'question_text' => 'Question text for question number 110?',
'question_type' => QAType::FREE_TEXT,
'next_nested_question' => 1000, //1000 //4 digits - second level
'next_main_question' => 20,
'is_start' => false,
'is_end' => false,
],
[
'question_number' => 300,
'question_text' => 'Question text for question number 300?',
'question_type' => QAType::MULTIPLE_CHOICES,
'next_main_question' => 40,
'is_start' => false,
'is_end' => false,
],
[
'question_number' => 600,
'question_text' => 'Shipping Fee Calculations',
'question_type' => QAType::ANSWER,
'is_start' => false,
'is_end' => true,
],
[
'question_number' => 700,
'question_text' => 'Please enter your measurements',
'question_type' => QAType::FREE_TEXT,
'next_nested_question' => 710,
'next_main_question' => 20,
'is_start' => false,
'is_end' => false,
],
[
'question_number' => 710,
'question_text' => 'Please upload the photo proof',
'question_type' => QAType::DOCUMENT_UPLOAD,
'next_main_question' => 60,
'is_start' => false,
'is_end' => false,
],
[
'question_number' => 800,
'question_text' => 'What is your name?',
'question_type' => QAType::FREE_TEXT,
'next_nested_question' => 810,
'is_start' => false,
'is_end' => false,
],
[
'question_number' => 810,
'question_text' => 'Click Next to speak to our customer service',
'question_type' => QAType::FREE_TEXT,
'is_start' => false,
'is_end' => true,
'end_text' => 'We have received your request and will response as soon as possible.',
],
[
'question_number' => 1000,
'question_text' => 'Question text for question number 1000?',
'question_type' => QAType::FREE_TEXT,
'next_nested_question' => 10000, //10000 - 5 digits - 3rd level
'next_main_question' => 20,
'is_start' => false,
'is_end' => false,
],
[
'question_number' => 10000,
'question_text' => 'Question text for question number 10000?',
'question_type' => QAType::FREE_TEXT,
'next_main_question' => 20,
'is_start' => false,
'is_end' => false,
],
];
break;
case 'Set 2':
$questions = [
[
'question_number' => 10,
'question_text' => 'How helpful is our agent towards resolving your issue?',
'question_type' => QAType::RATING_5_STARS,
'is_start' => true,
'is_end' => false,
],
[
'question_number' => 20,
'question_text' => 'How would you rate our customer service experience?',
'question_type' => QAType::RATING_5_STARS,
'is_start' => false,
'is_end' => true,
]
];
break;
case 'Set 3':
$questions = [
[
'question_number' => 10,
'question_text' => 'Is our service suite for you?',
'question_type' => QAType::MULTIPLE_CHOICES,
'is_start' => true,
'is_end' => false,
],
[
'question_number' => 20,
'question_text' => 'Can you rate our sales agent performance whether you comfortable when chatting with them',
'question_type' => QAType::RATING_5_STARS,
'is_start' => false,
'is_end' => true,
]
];
break;
case 'Set 4':
$questions = [
[
'question_number' => 10,
'question_text' => 'How satisfy you are after your first order?',
'question_type' => QAType::RATING_5_STARS,
'is_start' => true,
'is_end' => false,
]
];
break;
}
foreach ($questions as $key => $questionData) {
$question = new QAQuestions;
$question->question_number = $questionData['question_number'];
$question->question_text = $questionData['question_text'];
$question->question_type = $questionData['question_type'];
$question->questionnaire_set_id = $questionnaireSet->id;
if (isset($questionData['next_nested_question'])) {
$question->next_nested_question = $questionData['next_nested_question'];
}
if (isset($questionData['next_main_question'])) {
$question->next_main_question = $questionData['next_main_question'];
}
$question->is_start = $questionData['is_start'];
$question->is_end = $questionData['is_end'];
if (isset($questionData['end_text'])) {
$question->end_text = $questionData['end_text'];
}
$question->order = $key + 1;
$question->save();
}
}
}
}
+144
View File
@@ -0,0 +1,144 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\QAQuestionnaireSet;
use App\Models\QAQuestions;
use App\Classes\ValueObjects\Constants\QAType;
class QAQuestionsSeeder extends Seeder
{
public function run()
{
$questionnaireSets = [
[
'name' => 'Set 1',
'description' => 'Customer Support Satisfaction Survey',
'group' => 'feedback'
],
[
'name' => 'Set 2',
'description' => 'First Order Experience Feedback',
'group' => 'feedback'
],
[
'name' => 'Set 3',
'description' => 'Sales Inquiry Experience',
'group' => 'feedback'
],
];
foreach ($questionnaireSets as $set) {
$questionnaireSet = QAQuestionnaireSet::create([
'name' => $set['name'],
'description' => $set['description'],
'group' => $set['group'],
]);
$questions = [];
switch ($set['name']) {
case 'Set 1':
$questions = [
[
'question_number' => 10,
'question_text' => 'On a scale of 1 to 5, how satisfied are you with the time it took to receive a response?',
'question_type' => QAType::MULTIPLE_CHOICES,
'is_start' => true,
'is_end' => false,
],
[
'question_number' => 20,
'question_text' => 'Was your issue resolved during this interaction?',
'question_type' => QAType::MULTIPLE_CHOICES,
'is_start' => false,
'is_end' => false,
],
[
'question_number' => 30,
'question_text' => 'How clear and understandable was the communication from the support team?',
'question_type' => QAType::MULTIPLE_CHOICES,
'is_start' => false,
'is_end' => true,
]
];
break;
case 'Set 2':
$questions = [
[
'question_number' => 10,
'question_text' => 'Did you find what you were looking for without any issues?',
'question_type' => QAType::MULTIPLE_CHOICES,
'is_start' => true,
'is_end' => false,
],
[
'question_number' => 20,
'question_text' => 'Did the service meet your expectations?',
'question_type' => QAType::MULTIPLE_CHOICES,
'is_start' => false,
'is_end' => false,
],
[
'question_number' => 30,
'question_text' => 'On a scale of 1 to 5, how satisfied are you with the delivery time?',
'question_type' => QAType::MULTIPLE_CHOICES,
'is_start' => false,
'is_end' => true,
]
];
break;
case 'Set 3':
$questions = [
[
'question_number' => 10,
'question_text' => 'How quickly did our sales team respond to your inquiry?',
'question_type' => QAType::MULTIPLE_CHOICES,
'is_start' => true,
'is_end' => false,
],
[
'question_number' => 20,
'question_text' => 'Was the information provided by our sales team clear and easy to understand?',
'question_type' => QAType::MULTIPLE_CHOICES,
'is_start' => false,
'is_end' => false,
],
[
'question_number' => 30,
'question_text' => 'After interacting with our sales team, how likely are you to use our service?',
'question_type' => QAType::MULTIPLE_CHOICES,
'is_start' => false,
'is_end' => true,
]
];
break;
}
foreach ($questions as $key => $questionData) {
$question = new QAQuestions;
$question->question_number = $questionData['question_number'];
$question->question_text = $questionData['question_text'];
$question->question_type = $questionData['question_type'];
$question->questionnaire_set_id = $questionnaireSet->id;
if (isset($questionData['next_nested_question'])) {
$question->next_nested_question = $questionData['next_nested_question'];
}
if (isset($questionData['next_main_question'])) {
$question->next_main_question = $questionData['next_main_question'];
}
$question->is_start = $questionData['is_start'];
$question->is_end = $questionData['is_end'];
if (isset($questionData['end_text'])) {
$question->end_text = $questionData['end_text'];
}
$question->order = $key + 1;
$question->save();
}
}
}
}
@@ -0,0 +1,17 @@
<template>
<div class="row parentContainer">
<div class="col-1">{{ item.questionnaire.description }}</div>
<div class="col-2"> <p>{{ item.question_text }}</p> </div>
<div class="col-1">{{ item.free_text_answer }}</div>
<div class="col-1">{{ item.source_system }}</div>
<div class="col-1">{{ item.source_marking }}</div>
<div class="col-2">{{ item.source_email }}</div>
<div class="col-1">{{ item.created_at }}</div>
</div>
</template>
<script>
import componentHandler from '../../../general/mixins/componentHandler';
export default {
mixins: [componentHandler]
}
</script>
@@ -0,0 +1,170 @@
<template>
<div class="container">
<div class="row">
<loading-component style="height: 50px; top: 0;" key="1" color="success" v-show="$store.getters.isLoading(section)"></loading-component>
<div class="col bg-white padding-40 b-rad-lg" v-if="!message">
<div class="row" v-for="(single_answer, index) in answers" :key="index" v-show="!$store.getters.isLoading(section)">
<div class="col">
<div class="row m-b-5 animate__animated animate__fadeInUpBig animate__fast" v-if="error">
<div class="col">
<small class="bold fs-10 text-danger">{{error}}</small>
</div>
</div>
<div class="row m-b-20">
<div class="col">
<h3>{{questions[index].question_text}}</h3>
</div>
</div>
<div class="row m-b-10" v-if="questions[index].question_type === 4" >
<div class="col" v-for="ans in questions[index].question_answers">
<div v-html="ans.display_text"></div>
</div>
</div>
<div class="row m-b-25" v-else-if="questions[index].question_type === 1" >
<div class="col" v-for="ans in questions[index].question_answers">
<div :class="'question-answers-' + index">
<div class="btn btn-xs btn-block p-t-35 p-b-35 fs-16" :answerValue="ans.value" :answerId=ans.id @click="addClass($event, 'question-answers-' + index, index)">{{ ans.display_text }}</div>
</div>
</div>
<!-- <div class="col" >-->
<!-- <validation-wrapper-component :validator="$v.answers.$each[index]" class="row">-->
<!-- <div class="col" v-for="ans in questions[index].question_answers">-->
<!-- <div :class="'question-answers-' + index">-->
<!-- <div class="btn btn-xs btn-block p-t-35 p-b-35 fs-16" :answerValue="ans.value" :answerId=ans.id @click="addClass($event, 'question-answers-' + index, index)">{{ ans.display_text }}</div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </validation-wrapper-component>-->
<!-- </div>-->
</div>
<div class="row m-b-10" v-else-if="questions[index].question_type === 6" >
<div class="col" >
<validation-wrapper-component :validator="$v.answers.$each[index]" class="col">
<div class="rating">
<span
v-for="(star, i) in stars"
:key="i"
@click="setRating(i + 1, index)"
:class="{
'filled': i < single_answer.answer,
'unfilled': i >= single_answer.answer
}"
>
<i class="fa fa-star"></i>
</span>
</div>
<p>Your rating: {{ single_answer.answer }} stars</p>
</validation-wrapper-component>
</div>
</div>
<div class="row m-b-10" v-else>
<div class="col" >
<validation-wrapper-component :validator="$v.answers.$each[index]">
<label>Answer</label>
<input type="text" class="form-control" v-model="single_answer.answer" @input="formTouched = true">
</validation-wrapper-component>
</div>
</div>
</div>
</div>
<div class="row" v-if="!$store.getters.isLoading(section)">
<div class="col text-center">
<div class="btn btn-lg btn-info b-rad-none padding-25 w-50 fs-20" :disabled="!$v.$dirty || !$v.$valid" @click="formTouched = true; submitForm()">Submit Feedback</div>
</div>
</div>
</div>
<div class="col bg-white padding-40 b-rad-lg" v-else>
<div class="d-flex justify-content-center align-items-center h-100">
{{ message }}
</div>
</div>
</div>
</div>
</template>
<script>
import { required } from "vuelidate/lib/validators";
export default {
props: {
questions:{
type: Array,
required: true
},
token: {
type: String,
required: true,
}
},
data(){
return {
section: 'feedbackForm',
answers: this.questions.map(function (item) {
return {
questionId: item.id,
answer: '',
answerId: 0
};
}),
error: null,
message: '',
stars: [1, 2, 3, 4, 5],
}
},
validations: {
answers: {
$each: {
answer: { required }
}
}
},
created(){
this.$store.dispatch('updateListQueue', {'name': this.section});
},
methods: {
successHandler(response){
this.$store.dispatch('completeList', {'name': this.section, 'data': []});
this.message = response.payload.data.message;
},
addClass(event, cls, index) {
const div = event.target;
this.answers[index].answer = div.getAttribute('answerValue');
this.answers[index].answerId = div.getAttribute('answerId');
this.removeClass(cls);
div.classList.add('btn-success');
},
setRating(value, index) {
this.answers[index].answer = value;
this.answers[index].answerId = 0;
},
removeClass(cls) {
document.getElementsByClassName(cls).forEach(el => {
const btnPrimaryEl = el.getElementsByClassName('btn-success')[0];
if (btnPrimaryEl) {
btnPrimaryEl.classList.remove('btn-success');
}
});
},
submitForm() {
this.parameters = {}
this.parameters.answers = this.answers;
this.parameters.token = this.token;
this.submit(this.route('api.feedback.submit.questions'), 'post', this.section, true, true);
}
}
}
</script>
<style scoped>
.rating {
font-size: 24px;
}
.rating span {
cursor: pointer;
margin-right: 5px;
color: #ffc107; /* Yellow color for filled stars */
}
.rating span.unfilled {
color: #ccc; /* Gray color for unfilled stars */
}
</style>
@@ -0,0 +1,99 @@
<template>
<div class="row">
<div class="col bg-white padding-40 b-rad-lg">
<loading-component style="height: 50px; top: 0;" key="1" color="success" v-show="$store.getters.isLoading(section)"></loading-component>
<div class="row" v-show="!$store.getters.isLoading(section)">
<div class="col">
<div class="row m-b-5 animate__animated animate__fadeInUpBig animate__fast" v-if="error">
<div class="col">
<small class="bold fs-10 text-danger">{{error}}</small>
</div>
</div>
<div class="row m-b-20">
<div class="col-12 col-md-8">
<validation-wrapper-component selectable class="m-b-15" :validator="$v.parameters.question_set">
<label class="text-primary">Question Set</label>
<select-component :options="[{'id': 1, 'text': 'Customer Support Satisfaction Survey'}, {'id': 2, 'text': 'First Order Experience Feedback'}, {'id': 3, 'text': 'Sales Inquiry Experience'}]" v-model="parameters.question_set"></select-component>
</validation-wrapper-component>
</div>
<div class="col-12 col-md-8">
<validation-wrapper-component selectable class="m-b-15" :validator="$v.parameters.system">
<label class="text-primary">System</label>
<select-component :options="[{'id': 1, 'text': 'IZYIM'}, {'id': 2, 'text': 'Exchange'}, {'id': 3, 'text': 'Lite'}]" v-model="parameters.system"></select-component>
</validation-wrapper-component>
</div>
<div class="col-12 m-b-15 col-md-8">
<validation-wrapper-component :validator="$v.parameters.customer_marking">
<label>Customer Marking</label>
<input type="text" class="form-control" v-model="parameters.customer_marking" @input="formTouched = true">
</validation-wrapper-component>
</div>
<div class="col-12 m-b-15 col-md-8">
<validation-wrapper-component :validator="$v.parameters.email">
<label>Email</label>
<input type="text" class="form-control" v-model="parameters.email" @input="formTouched = true">
</validation-wrapper-component>
</div>
</div>
</div>
</div>
<div class="row" v-show="!$store.getters.isLoading(section)">
<div class="col-md-8">
<div class="btn btn-sm btn-primary btn-block b-rad-none" :disabled="!$v.$dirty || !$v.$valid" @click="formTouched = true; submitForm()">Generate URL</div>
</div>
</div>
<div class="row m-b-20 m-t-10" v-show="url">
<div class="col-12 col-md-8">
URL Generated: <a target="_blank" :href="'/feedback/' + url">Click here to open at new tab</a>
</div>
</div>
</div>
</div>
</template>
<script>
import { required } from "vuelidate/lib/validators";
export default {
data(){
return {
section: 'generateFeedbackLinkForm',
url: '',
error: null,
parameters: {
system: '',
customer_marking:'',
email: '',
question_set: '',
}
}
},
validations: {
parameters: {
system: { required },
customer_marking: { required },
email: { required },
question_set: { required },
}
},
methods: {
successHandler(response){
this.url = response.payload.data.token;
this.reset();
},
submitForm() {
this.url = '';
this.submit(this.route('api.helpmenu.feedback.url.generate'), 'post', this.section, true, true);
},
reset(){
this.parameters.system = '';
this.parameters.customer_marking = '';
this.parameters.email = '';
this.parameters.question_set = '';
this.$v.$reset();
}
}
}
</script>
@@ -0,0 +1,11 @@
<template>
<div class="row">
<div class="col-12">
<generate-feedback-link-form-component></generate-feedback-link-form-component>
</div>
</div>
</template>
<script>
export default {
}
</script>
@@ -0,0 +1,57 @@
<template>
<div class="row">
<loading-component style="height: 50px; top: 0;" key="1" color="success" v-show="$store.getters.isLoading(section)"></loading-component>
<div class="col-12" v-if="questions.length > 0">
<feedback-form-component :questions="questions" :token="token"></feedback-form-component>
</div>
</div>
</template>
<script>
export default {
props: {
token: {
type: String,
required: true,
}
},
data(){
return {
section: 'feedbackCustomerSection',
questions: []
}
},
computed: {
pendingQueue () {
return this.$store.getters.isInCompleteQueue(this.section);
}
},
watch: {
pendingQueue(inComplete){
if(inComplete){
this.fetchQuetions();
}
}
},
created(){
this.$store.dispatch('updateListQueue', {'name': this.section});
},
methods: {
fetchQuetions(){
this.parameters = {}
this.parameters.token = this.token;
this.submit(route('api.feedback.list.question'), 'post', this.section, false, false);
// var filters = {'questionnaire_set_id': 1};
// this.submit(route('api.helpmenu.list.question', this.id) + '?filters=' + JSON.stringify(filters), 'get', this.section, false, false);
},
successHandler(response){
this.$store.dispatch('completeList', {'name': this.section, 'data': []});
this.questions = response.payload.data;
},
errorHandler(error, status){
if(status == 404){
window.location.href = this.route('error.404');
}
}
}
}
</script>
@@ -0,0 +1,68 @@
<template>
<div class="parentContainer">
<div class="floating-button">
<button class="requestModal round-button" data-type="helpMenu">
<i class="fa fa-info"></i>
<span class="beta-label">Beta</span>
</button>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="helpMenu">
<help-menu-form-component></help-menu-form-component>
</modal-component>
</div>
</div>
</template>
<script>
export default {
};
</script>
<style scoped>
.floating-button {
position: fixed;
z-index: 9999;
bottom: 95px;
right: 24px;
}
.round-button {
width: 60px;
height: 60px;
background-color: #007bff;
color: white;
border: none;
border-radius: 50%;
font-size: 24px;
cursor: pointer;
outline: none;
}
.round-button:hover {
background-color: #0056b3;
}
.beta-label {
position: absolute;
top: 44px;
left: 88%;
transform: translateX(-50%);
background-color: #ffee00;
color: black;
padding: 0px 4px;
border-radius: 5px;
font-size: 11px;
}
@media (max-height: 600px) {
.floating-button {
bottom: 85px;
right: 14px;
}
.round-button {
width: 54px;
height: 54px;
}
}
</style>
@@ -0,0 +1,224 @@
<template>
<div class="row">
<div class="col bg-white padding-40 b-rad-lg">
<loading-component style="height: 50px; top: 0;" key="1" color="success" v-show="$store.getters.isLoading(section)"></loading-component>
<div class="row" v-if="question" v-show="!$store.getters.isLoading(section)">
<div class="col">
<div class="row m-b-5 animate__animated animate__fadeInUpBig animate__fast" v-if="error">
<div class="col">
<small class="bold fs-10 text-danger">{{error}}</small>
</div>
</div>
<div class="row m-b-20">
<div class="col">
<h3>{{question.question_text}}</h3>
</div>
</div>
<div class="row m-b-10" v-if="question.question_type === 4" >
<div class="col" v-for="ans in question.question_answers">
<div v-html="ans.display_text"></div>
</div>
</div>
<div class="row m-b-15" v-else-if="question.question_type === 3">
<div class="col">
<file-input-component :validator="$v.files" v-model="files">
<template slot="label">
<div class="font-heading fs-11 all-caps">Photo or File</div>
</template>
<template slot="tips">
<div class="row" v-show="false">
<div class="col">
<div class="row m-b-20">
<div class="col">
<div class="font-heading fs-11 text-warning m-b-10">{{ documentType === 0 ? 'IC': 'SSM registration'}} number shown in the photo should tally with {{ documentType === 0 ? 'IC': 'SSM registration'}} number provided above.</div>
<div class="font-heading fs-11 muted">Tips on how your photo should look</div>
</div>
</div>
</div>
</div>
</template>
</file-input-component>
</div>
</div>
<div class="row m-b-10" v-show="question.is_end === 0" v-else-if="question.question_type === 1" >
<validation-wrapper-component :validator="$v.answer" class="col">
<div class="col" v-for="ans in question.question_answers">
<div class="col question.answers">
<div class="btn btn-xs btn-block" :answerValue="ans.value" :answerId=ans.id @click="addClass($event, 'question.answers')">{{ ans.display_text }}</div>
</div>
</div>
</validation-wrapper-component>
</div>
<div class="row m-b-10" v-show="question.is_end === 0" v-else>
<div class="col" >
<validation-wrapper-component :validator="$v.answer">
<label>Answer</label>
<input type="text" class="form-control" v-model="answer" @input="formTouched = true">
</validation-wrapper-component>
</div>
</div>
<div class="row">
<div class="col p-r-5">
<div class="btn btn-sm btn-default bg-master-lightest btn-block b-rad-none" @click=" submitForm('previous')">Previous</div>
</div>
<div class="col p-r-5">
<div class="btn btn-sm btn-default bg-master-lightest btn-block b-rad-none" data-dismiss="modal">Cancel</div>
</div>
<div class="col p-l-5">
<div class="btn btn-sm btn-primary btn-block b-rad-none" :disabled="!$v.$dirty || !$v.$valid" @click="formTouched = true; submitForm('next')">{{ question.is_end === 0 ? 'Next' : 'Finish' }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { required } from "vuelidate/lib/validators";
export default {
data(){
return {
section: 'helpMenuForm',
showAnswerInput: false,
showUploadInput: false,
formTouched: false,
question: null,
answer: '',
answerId: 0,
direction: 'next',
documentType: 1,
files: [],
error: null
}
},
validations() {
return {
answer: {
required: this.formTouched && this.showAnswerInput ? required : false,
},
files: {
required: this.formTouched && this.showUploadInput ? required : false,
}
};
},
computed: {
pendingQueue () {
return this.$store.getters.isInCompleteQueue(this.section);
},
parametersExist() {
return Boolean(this.answer);
}
},
watch: {
pendingQueue(inComplete, oldValue){
if(inComplete){
this.fetchFirstQuestion();
}
}
},
created(){
this.$store.dispatch('updateListQueue', {'name': this.section});
},
methods: {
fetchFirstQuestion(){
this.submit(route('api.helpmenu.first.question', 4), 'get', this.section, false, false);
},
successHandler(response){
this.$store.dispatch('completeList', {'name': this.section, 'data': []});
this.question = response.payload.data;
this.reset();
this.removeClass('question.answers');
if(this.question.answer != null && this.direction == "previous"){
this.answer = this.question.answer.free_text_answer;
}
},
errorHandler(error){
// this.error = error.message;
this.error = 'We are sorry, something went wrong. Please contact us via live chat.';
},
submitForm(direction) {
this.parameters = {}
this.error = null;
this.direction = direction;
if(this.question.question_type === 3){
this.showAnswerInput = false;
this.showUploadInput = true;
}
else if(this.question.question_type === 1 || (this.question.question_type === 2)){
this.showAnswerInput = true;
this.showUploadInput = false;
}
if(direction === 'next'){
this.parameters.question = this.question;
this.parameters.answer = this.answer;
this.parameters.answerId = this.answerId;
this.parameters.answerObj = this.question.question_answers.find(item => item.id === Number(this.answerId));
this.parameters.files = this.files;
if(this.question.question_type === 4)
{
this.closeModal();
this.reset();
this.fetchFirstQuestion();
}
else{
if(this.question.is_end){
if(this.question.question_type === 5){
this.submit(this.route('api.helpmenu.next.question'), 'post', this.section, false, false);
this.closeModal();
this.reset();
}
else{
$crisp.push(["do", "chat:open"]);
const result = [
...this.question.questionnaire_answers.map(item => [item.question_text.replace(/ /g, "_").replace(/\W/g, ''), item.free_text_answer])
];
let payload = [];
payload.push(result);
$crisp.push(["set", "session:data", payload]);
$crisp.push(["do", "message:send", ["text", "Hello there!"]]); //cief todo: need to update what message to send from customer to operator
this.closeModal();
this.reset();
this.fetchFirstQuestion();
}
}
else{
this.submit(this.route('api.helpmenu.next.question'), 'post', this.section, false, false);
}
}
}
else if(direction === 'previous'){
this.formTouched = false;
this.parameters.question = this.question;
this.parameters.isPrevious = true;
this.submit(this.route('api.helpmenu.next.question'), 'post', this.section, false, false);
}
},
reset() {
this.parameters = null;
this.answer = '';
this.answerId = 0;
this.files = [];
this.formTouched = false;
this.showAnswerInput = false;
this.showUploadInput = false;
this.error = null;
},
addClass(event, cls) {
const div = event.target;
this.answer = div.getAttribute('answerValue');
this.answerId = div.getAttribute('answerId');
this.removeClass(cls);
div.classList.add('btn-primary');
},
removeClass(cls) {
document.getElementsByClassName(cls).forEach(el => {
const btnPrimaryEl = el.getElementsByClassName('btn-primary')[0];
if (btnPrimaryEl) {
btnPrimaryEl.classList.remove('btn-primary');
}
});
}
},
}
</script>
@@ -36,6 +36,7 @@
</div>
</template>
<script>
import { required } from "vuelidate/lib/validators";
import ModalFormHandler from '../../../general/mixins/modalFormHandler';
export default {
props: {
@@ -58,9 +59,7 @@
},
validations: {
parameters: {
content: {
required: false
}
content: { required: required },
}
},
methods: {
@@ -71,4 +70,4 @@
mixins: [ModalFormHandler]
}
</script>
</script>
@@ -25,9 +25,13 @@
</div>
<div class="col d-flex">
<div class="btn btn-xs btn-outline-danger b-rad-none pointer requestModal align-items-center d-flex" data-type="changeOrderNo" v-if="$store.getters.isSuperAdmin">Change Order Number</div>
<!-- <div class="btn btn-xs btn-outline-danger b-rad-none pointer requestModal align-items-center d-flex m-l-10" data-type="helpMenu" v-if="$store.getters.isSuperAdmin">Help Menu</div> -->
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="changeOrderNo">
<change-order-number-form-component :section="section" :data="order"></change-order-number-form-component>
</modal-component>
<!-- <modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="helpMenu">
<help-menu-form-component></help-menu-form-component>
</modal-component> -->
</div>
</div>
<div class="row m-b-20">
@@ -500,4 +504,4 @@
}
}
}
</script>
</script>
@@ -25,9 +25,13 @@
</div>
<div class="col d-flex">
<div class="btn btn-xs btn-outline-danger b-rad-none pointer requestModal align-items-center d-flex" data-type="changeOrderNo" v-if="$store.getters.isSuperAdmin">Change Order Number</div>
<!-- <div class="btn btn-xs btn-outline-danger b-rad-none pointer requestModal align-items-center d-flex m-l-10" data-type="helpMenu" v-if="$store.getters.isSuperAdmin">Help Menu</div> -->
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="changeOrderNo">
<change-order-number-form-component :section="section" :data="order"></change-order-number-form-component>
</modal-component>
<!-- <modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="helpMenu">
<help-menu-form-component></help-menu-form-component>
</modal-component> -->
</div>
</div>
<div class="row m-b-20">
@@ -200,4 +204,4 @@
}
}
}
</script>
</script>
+6 -2
View File
@@ -1,7 +1,11 @@
export default {
methods: {
routesGuard(){
(!this.$store.getters.isAuthenticated && this.isProtectedRoute()&& this.isWithTokenRoute()) ? window.location.href = window.location.href.indexOf(this.route('last_mile_delivery.login')) === 0 ? this.route('last_mile_delivery.login') : this.route('login') : '';
if(!this.$store.getters.isAuthenticated && this.isProtectedRoute()&& this.isWithTokenRoute()){
if(window.location.href.indexOf(this.route('feedback.customer')) !== 0){
window.location.href = window.location.href.indexOf(this.route('last_mile_delivery.login')) === 0 ? this.route('last_mile_delivery.login') : this.route('login')
}
}
(this.$store.getters.isAuthenticated && !this.isProtectedRoute()&& this.isWithTokenRoute()) ? window.location.href = [7, 8].includes(this.$store.getters.getCompanyModuleType) ? this.route('last_mile_delivery.dashboard') : this.route('dashboard') : '';
},
isProtectedRoute(){
@@ -17,4 +21,4 @@ export default {
}
}
}
}
+5
View File
@@ -0,0 +1,5 @@
@extends('errors::illustrated-layout')
@section('title', __('Not Found'))
@section('code', '404')
@section('message', __('Not Found'))

Some files were not shown because too many files have changed in this diff Show More