New Customer Satisfaction Feedback Module

This commit is contained in:
Dillon
2023-09-21 00:19:21 +08:00
parent 60fbe77829
commit 42561a7c56
53 changed files with 1546 additions and 200 deletions
@@ -32,12 +32,12 @@ class UploadDocumentForHelpMenuProcessor
/**
* @param Request $request
* @param $filesUpload
* @param QAUserAnswerSelected qaUserAnswerSelected
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function execute(Request $request, QAUserAnswerSelected $qaUserAnswerSelected) {
$object = new DocumentObject("HELP_MENU", $request->input('files'),
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 */
@@ -4,7 +4,7 @@ namespace App\Classes\Modules\HelpMenu\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\HelpMenu\Standards\Rules\CanFetchHelpMenuQuestionList;
use App\Classes\Modules\HelpMenu\Standards\Rules\CanFetchHelpMenuQuestion;
use App\Classes\Modules\HelpMenu\Processors\FetchFirstHelpMenuQuestionProcessor;
use App\Http\Resources\HelpMenuQuestionResource;
use ErrorException;
@@ -25,20 +25,20 @@ class FetchHelpMenuQuestionLogic extends AbstractControllerLogic
];
}
/** @var CanFetchHelpMenuQuestionList */
private $canFetchHelpMenuQuestionList;
/** @var CanFetchHelpMenuQuestion */
private $canFetchHelpMenuQuestion;
/** @var FetchFirstHelpMenuQuestionProcessor */
private $fetchFirstHelpMenuQuestionProcessor;
/**
* FetchHelpMenuQuestionLogic constructor.
* @param CanFetchHelpMenuQuestionList $canFetchHelpMenuQuestionList
* @param CanFetchHelpMenuQuestion $canFetchHelpMenuQuestion
* @param FetchFirstHelpMenuQuestionProcessor $fetchFirstHelpMenuQuestionProcessor
*/
public function __construct(CanFetchHelpMenuQuestionList $canFetchHelpMenuQuestionList, FetchFirstHelpMenuQuestionProcessor $fetchFirstHelpMenuQuestionProcessor)
public function __construct(CanFetchHelpMenuQuestion $canFetchHelpMenuQuestion, FetchFirstHelpMenuQuestionProcessor $fetchFirstHelpMenuQuestionProcessor)
{
$this->canFetchHelpMenuQuestionList = $canFetchHelpMenuQuestionList;
$this->canFetchHelpMenuQuestion = $canFetchHelpMenuQuestion;
$this->fetchFirstHelpMenuQuestionProcessor = $fetchFirstHelpMenuQuestionProcessor;
}
@@ -50,7 +50,7 @@ class FetchHelpMenuQuestionLogic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
$this->canFetchHelpMenuQuestionList->passes();
$this->canFetchHelpMenuQuestion->passes();
$userId = Auth::user()->id;
@@ -0,0 +1,54 @@
<?php
namespace App\Classes\Modules\HelpMenu\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\HelpMenu\Standards\Rules\CanGenerateFeedbackUrl;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
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;
/**
* GenerateFeedbackUrlLogic constructor.
* @param CanGenerateFeedbackUrl $canGenerateFeedbackUrl
*/
public function __construct(CanGenerateFeedbackUrl $canGenerateFeedbackUrl)
{
$this->canGenerateFeedbackUrl = $canGenerateFeedbackUrl;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$this->canGenerateFeedbackUrl->passes();
$originalText = $request->input('system') . '|' . $request->input('customer_marking'). '|' . $request->input('email'). '|' . $request->input('question_set');
$resource = ['token' => Crypt::encryptString($originalText)];
return $this->response(['data' => $resource]);
}
}
@@ -0,0 +1,71 @@
<?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\Standards\Rules\CanListHelpMenuQuestions;
use App\Http\Resources\HelpMenuQuestionResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
use App\Classes\Exceptions\ResourceNotFoundException;
class ListHelpMenuQuestionsLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Retrieved Questions',
'message' => 'You have successfully retrieved a list of Questions'
];
}
/** @var CanListHelpMenuQuestions */
private $canListHelpMenuQuestions;
/** @var ListsHelpMenuQuestions */
private $listsHelpMenuQuestions;
/**
* ListHelpMenuQuestionsLogic constructor.
* @param CanListHelpMenuQuestions $canListHelpMenuQuestions
* @param ListsHelpMenuQuestions $listsHelpMenuQuestions
*/
public function __construct(CanListHelpMenuQuestions $canListHelpMenuQuestions, ListsHelpMenuQuestions $listsHelpMenuQuestions)
{
$this->canListHelpMenuQuestions = $canListHelpMenuQuestions;
$this->listsHelpMenuQuestions = $listsHelpMenuQuestions;
}
/**
* @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
{
$this->canListHelpMenuQuestions->passes();
try{
$token = $request->input('token');
$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));
} catch(\Exception $exception){
throw new ResourceNotFoundException($exception->getMessage());
}
}
}
@@ -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 ListQALogic 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;
/**
* ListQALogic 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,80 @@
<?php
namespace App\Classes\Modules\HelpMenu\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\HelpMenu\Processors\SaveHelpMenuAnswerProcessor;
use App\Classes\Modules\HelpMenu\Processors\UserSourceForQAProcessor;
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 SaveHelpMenuAnswerProcessor */
private $saveHelpMenuAnswerProcessor;
/** @var UserSourceForQAProcessor */
private $userSourceForQAProcessor;
/**
* SubmitQAQuestionsLogic constructor.
* @param SaveHelpMenuAnswerProcessor $saveHelpMenuAnswerProcessor
* @param UserSourceForQAProcessor $userSourceForQAProcessor
*/
public function __construct(SaveHelpMenuAnswerProcessor $saveHelpMenuAnswerProcessor, UserSourceForQAProcessor $userSourceForQAProcessor)
{
$this->saveHelpMenuAnswerProcessor = $saveHelpMenuAnswerProcessor;
$this->userSourceForQAProcessor = $userSourceForQAProcessor;
}
/**
* @param Request $request
* @return JsonResponse
* @throws ErrorException
*/
public function logic(Request $request) : JsonResponse
{
$token = $request->input('token');
$userId = 0;
$sourceId = 0;
try {
$decriptedToken = Crypt::decryptString($token);
$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->saveHelpMenuAnswerProcessor->execute($userId, $sourceId, $answer['questionId'], $answer['answer'], $answer['answerId'], $filesUpload);
}
$response = ['message' => 'Thank you for your feedback.'];
return $this->response(['data' => $response]);
}
}
@@ -5,7 +5,7 @@ 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\CanFetchHelpMenuQuestionList;
use App\Classes\Modules\HelpMenu\Standards\Rules\CanFetchHelpMenuQuestion;
use App\Classes\Modules\HelpMenu\Processors\SaveHelpMenuAnswerProcessor;
use App\Classes\Modules\HelpMenu\Processors\DeleteHelpMenuAnswerProcessor;
use App\Classes\Modules\HelpMenu\Processors\FetchNextHelpMenuQuestionProcessor;
@@ -31,8 +31,8 @@ class UpdateHelpMenuNextQuestionLogic extends AbstractControllerLogic
];
}
/** @var CanFetchHelpMenuQuestionList */
private $canFetchHelpMenuQuestionList;
/** @var CanFetchHelpMenuQuestion */
private $canFetchHelpMenuQuestion;
/** @var SaveHelpMenuAnswerProcessor */
private $saveHelpMenuAnswerProcessor;
@@ -54,15 +54,15 @@ class UpdateHelpMenuNextQuestionLogic extends AbstractControllerLogic
/**
* UpdateHelpMenuNextQuestionLogic constructor.
* @param CanFetchHelpMenuQuestionList $canFetchHelpMenuQuestionList
* @param CanFetchHelpMenuQuestion $canFetchHelpMenuQuestion
* @param SaveHelpMenuAnswerProcessor $saveHelpMenuAnswerProcessor
* @param FetchNextHelpMenuQuestionProcessor $fetchNextHelpMenuQuestionProcessor
* @param FetchFirstHelpMenuQuestionProcessor $fetchFirstHelpMenuQuestionProcessor
* @param DeleteHelpMenuAnswerProcessor $deleteHelpMenuAnswerProcessor
*/
public function __construct(CanFetchHelpMenuQuestionList $canFetchHelpMenuQuestionList, SaveHelpMenuAnswerProcessor $saveHelpMenuAnswerProcessor, FetchNextHelpMenuQuestionProcessor $fetchNextHelpMenuQuestionProcessor, FetchFirstHelpMenuQuestionProcessor $fetchFirstHelpMenuQuestionProcessor, CreatesPerfexCRMSupportTicket $createsPerfexCRMSupportTicket, FetchesPerfexCRMCustomer $fetchesPerfexCRMCustomer, DeleteHelpMenuAnswerProcessor $deleteHelpMenuAnswerProcessor)
public function __construct(CanFetchHelpMenuQuestion $canFetchHelpMenuQuestion, SaveHelpMenuAnswerProcessor $saveHelpMenuAnswerProcessor, FetchNextHelpMenuQuestionProcessor $fetchNextHelpMenuQuestionProcessor, FetchFirstHelpMenuQuestionProcessor $fetchFirstHelpMenuQuestionProcessor, CreatesPerfexCRMSupportTicket $createsPerfexCRMSupportTicket, FetchesPerfexCRMCustomer $fetchesPerfexCRMCustomer, DeleteHelpMenuAnswerProcessor $deleteHelpMenuAnswerProcessor)
{
$this->canFetchHelpMenuQuestionList = $canFetchHelpMenuQuestionList;
$this->canFetchHelpMenuQuestion = $canFetchHelpMenuQuestion;
$this->saveHelpMenuAnswerProcessor = $saveHelpMenuAnswerProcessor;
$this->fetchNextHelpMenuQuestionProcessor = $fetchNextHelpMenuQuestionProcessor;
$this->fetchFirstHelpMenuQuestionProcessor = $fetchFirstHelpMenuQuestionProcessor;
@@ -85,14 +85,20 @@ class UpdateHelpMenuNextQuestionLogic extends AbstractControllerLogic
$questionId = $currentQuestion['id'];
$questionType = $currentQuestion['question_type'];
$this->canFetchHelpMenuQuestionList->passes();
$this->canFetchHelpMenuQuestion->passes();
//Delete answer
$this->deleteHelpMenuAnswerProcessor->execute($userId, $questionId, $request);
//Save answer given by user
if (!$request->has('isPrevious')) {
$this->saveHelpMenuAnswerProcessor->execute($userId, $questionId, $request);
$filesUpload = $request->input('files');
$answerOptionId = 0;
if ($request->has('answerObj')) {
$answerOptionId = intval($request->answerObj['id']);
}
$answerInText = $request->answer;
$this->saveHelpMenuAnswerProcessor->execute($userId, 0, $questionId, $answerInText, $answerOptionId, $filesUpload);
}
//Create ticket at crm
@@ -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;
}
}
@@ -4,32 +4,32 @@ namespace App\Classes\Modules\HelpMenu\Processors;
use App\Models\QAUserAnswerSelected;
use App\Classes\Modules\HelpMenu\Services\FetchesHelpMenuUserAnswerSelected;
use App\Classes\Modules\HelpMenu\Services\FetchesHelpMenuUserAnswerSelectedList;
use App\Classes\Modules\HelpMenu\Services\ListsHelpMenuUserAnswerSelected;
class DeleteHelpMenuAnswerProcessor
{
/** @var FetchesHelpMenuUserAnswerSelected */
private $fetchesHelpMenuUserAnswerSelected;
/** @var FetchesHelpMenuUserAnswerSelectedList */
private $fetchesHelpMenuUserAnswerSelectedList;
/** @var ListsHelpMenuUserAnswerSelected */
private $listsHelpMenuUserAnswerSelected;
/**
* DeleteHelpMenuAnswerProcessor constructor.
* @param FetchesHelpMenuUserAnswerSelected $fetchesHelpMenuUserAnswerSelected
* @param FetchesHelpMenuUserAnswerSelectedList $fetchesHelpMenuUserAnswerSelectedList
* @param ListsHelpMenuUserAnswerSelected $listsHelpMenuUserAnswerSelected
*/
public function __construct(FetchesHelpMenuUserAnswerSelected $fetchesHelpMenuUserAnswerSelected, FetchesHelpMenuUserAnswerSelectedList $fetchesHelpMenuUserAnswerSelectedList)
public function __construct(FetchesHelpMenuUserAnswerSelected $fetchesHelpMenuUserAnswerSelected, ListsHelpMenuUserAnswerSelected $listsHelpMenuUserAnswerSelected)
{
$this->fetchesHelpMenuUserAnswerSelected = $fetchesHelpMenuUserAnswerSelected;
$this->fetchesHelpMenuUserAnswerSelectedList = $fetchesHelpMenuUserAnswerSelectedList;
$this->listsHelpMenuUserAnswerSelected = $listsHelpMenuUserAnswerSelected;
}
public function execute($userId, $questionId, $request){
if ($request->has('isPrevious')) {
//Get current and previous question's answer
try{
$selectedAnswer = $this->fetchesHelpMenuUserAnswerSelectedList->execute(['user_id' => $userId, 'question_id' => $questionId, 'order_by' => (object)['column' => 'id','DESC' => true]])[0];
$selectedAnswer = $this->listsHelpMenuUserAnswerSelected->execute(['user_id' => $userId, 'question_id' => $questionId, 'order_by' => (object)['column' => 'id','DESC' => true]])[0];
} catch (\Exception $exception){
$selectedAnswer = null;
}
@@ -4,7 +4,7 @@ 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\FetchesHelpMenuUserAnswerSelectedList;
use App\Classes\Modules\HelpMenu\Services\ListsHelpMenuUserAnswerSelected;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Classes\ValueObjects\Constants\QAType;
@@ -17,19 +17,19 @@ class FetchNextHelpMenuQuestionProcessor
/** @var FetchesHelpMenuUserAnswerSelected */
private $fetchesHelpMenuUserAnswerSelected;
/** @var FetchesHelpMenuUserAnswerSelectedList */
private $fetchesHelpMenuUserAnswerSelectedList;
/** @var ListsHelpMenuUserAnswerSelected */
private $listsHelpMenuUserAnswerSelected;
/**
* FetchNextHelpMenuQuestionProcessor constructor.
* @param FetchesHelpMenuQuestion $fetchesHelpMenuQuestion
* @param FetchesHelpMenuUserAnswerSelected $fetchesHelpMenuUserAnswerSelected
* @param FetchesHelpMenuUserAnswerSelectedList $fetchesHelpMenuUserAnswerSelectedList
* @param ListsHelpMenuUserAnswerSelected $listsHelpMenuUserAnswerSelected
*/
public function __construct(FetchesHelpMenuQuestion $fetchesHelpMenuQuestion, FetchesHelpMenuUserAnswerSelected $fetchesHelpMenuUserAnswerSelected, FetchesHelpMenuUserAnswerSelectedList $fetchesHelpMenuUserAnswerSelectedList)
public function __construct(FetchesHelpMenuQuestion $fetchesHelpMenuQuestion, FetchesHelpMenuUserAnswerSelected $fetchesHelpMenuUserAnswerSelected, ListsHelpMenuUserAnswerSelected $listsHelpMenuUserAnswerSelected)
{
$this->fetchesHelpMenuQuestion = $fetchesHelpMenuQuestion;
$this->fetchesHelpMenuUserAnswerSelected = $fetchesHelpMenuUserAnswerSelected;
$this->fetchesHelpMenuUserAnswerSelectedList = $fetchesHelpMenuUserAnswerSelectedList;
$this->listsHelpMenuUserAnswerSelected = $listsHelpMenuUserAnswerSelected;
}
public function execute(Request $request){
@@ -55,7 +55,7 @@ class FetchNextHelpMenuQuestionProcessor
if ($request->has('isPrevious')) {
$userId = Auth::user()->id;
$previousAnswer = $this->fetchesHelpMenuUserAnswerSelectedList->execute(['user_id' => $userId, 'order_by' => (object)['column' => 'id','DESC' => true]])[0];
$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' => 1, 'id' => $previousAnswer['question_id']]);
@@ -26,30 +26,29 @@ class SaveHelpMenuAnswerProcessor
$this->uploadDocumentForHelpMenuProcessor = $uploadDocumentForHelpMenuProcessor;
}
public function execute($userId, $questionId, $request){
$filesUpload = $request->input('files');
public function execute($userId, $sourceId, $questionId, $answerInText, $answerOptionId, $filesUpload){
$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, 'question_id' => $questionId]);
} catch (\Exception $exception){
$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;
if ($request->has('answerObj')) {
$answer->answer_option_id = intval($request->answerObj['id']);
}
$answer->free_text_answer = $request->answer;
$answer->answer_option_id = intval($answerOptionId);
$answer->free_text_answer = $answerInText;
$answer->save();
if($filesUpload){
$result = $this->uploadDocumentForHelpMenuProcessor->execute($request, $answer);
$result = $this->uploadDocumentForHelpMenuProcessor->execute($filesUpload, $answer);
$newData = array_map(function ($item) {
return [
'document_id' => $item->document_id,
@@ -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);
}
}
@@ -2,7 +2,6 @@
namespace App\Classes\Modules\HelpMenu\Services;
use App\Classes\General\Eloquent\AbstractFetchRecord;
use Illuminate\Database\Eloquent\Builder;
use App\Models\QAQuestions;
@@ -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\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();
}
}
@@ -6,14 +6,14 @@ use App\Classes\General\Eloquent\AbstractListRecord;
use Illuminate\Database\Eloquent\Builder;
use App\Models\QAUserAnswerSelected;
class FetchesHelpMenuUserAnswerSelectedList extends AbstractListRecord
class ListsHelpMenuUserAnswerSelected extends AbstractListRecord
{
/** @var QAUserAnswerSelected */
private $repository;
/**
* FetchesHelpMenuUserAnswerSelectedList constructor.
* ListsHelpMenuUserAnswerSelected constructor.
* @param QAUserAnswerSelected $repository
*/
public function __construct(QAUserAnswerSelected $repository)
@@ -5,8 +5,9 @@ namespace App\Classes\Modules\HelpMenu\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
class CanFetchHelpMenuQuestionList extends AbstractRule
class CanFetchHelpMenuQuestion extends AbstractRule
{
/**
* @return bool
*/
@@ -0,0 +1,38 @@
<?php
namespace App\Classes\Modules\HelpMenu\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
class CanGenerateFeedbackUrl 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,41 @@
<?php
namespace App\Classes\Modules\HelpMenu\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
class CanListHelpMenuQuestions 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,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';
}
}
}
@@ -15,4 +15,6 @@ final class QAType {
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\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,19 @@
<?php
namespace App\Http\Controllers\HelpMenu;
use App\Classes\Modules\HelpMenu\ControllersLogic\ListHelpMenuQuestionsLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListHelpMenuQuestionsController
{
/**
* @param Request $request
* @param ListHelpMenuQuestionsLogic $logic
* @return JsonResponse
*/
public function list(Request $request, ListHelpMenuQuestionsLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\HelpMenu;
use App\Classes\Modules\HelpMenu\ControllersLogic\ListQALogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListQAController
{
/**
* @param Request $request
* @param ListQALogic $logic
* @return JsonResponse
*/
public function list(Request $request, ListQALogic $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);
}
}
@@ -34,7 +34,7 @@ class HelpMenuQuestionResource extends JsonResource
'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)->get()),
'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,
@@ -0,0 +1,39 @@
<?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;
if($user){
$user_marking = $user->companyModule()->first()->inviters()->withPivot('invitee_reference')->first()->pivot->invitee_reference;
}
return [
'question_id' => $this->question_id,
'questionnaire_set_id' => $question ? $question->questionnaire_set_id : null,
'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,
];
}
}
+17
View File
@@ -21,4 +21,21 @@ class QAUserAnswerSelected extends AbstractModel implements Documentable
{
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');
}
}
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace App\Models;
class QAUserSource extends AbstractModel
{
protected $table = 'qa_user_source';
}
@@ -17,9 +17,9 @@ class CreateQAQuestionnaireSetsTable extends Migration
$table->id();
$table->string('name');
$table->string('description')->nullable();
$table->unsignedSmallInteger('order')->default(0);
$table->unsignedBigInteger('order')->default(0);
$table->unsignedBigInteger('next_set')->nullable();
$table->unsignedSmallInteger('version')->default(1);
$table->unsignedBigInteger('version')->default(1);
$table->timestamps();
$table->softDeletes();
});
@@ -24,7 +24,7 @@ class CreateQAQuestionsTable extends Migration
$table->tinyInteger('is_start');
$table->tinyInteger('is_end');
$table->string('end_text')->nullable();
$table->unsignedInteger('order')->default(0);
$table->unsignedBigInteger('order')->default(0);
$table->timestamps();
$table->softDeletes();
@@ -17,11 +17,15 @@ class CreateQAAnswerOptionsTable extends Migration
$table->id();
$table->text('display_text');
$table->string('value');
$table->unsignedSmallInteger('order')->default(0);
$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');
});
}
@@ -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');
}
}
@@ -15,7 +15,8 @@ class CreateQAUserAnswerSelectedTable extends Migration
{
Schema::create('qa_user_answer_selected', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_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();
@@ -24,7 +25,8 @@ class CreateQAUserAnswerSelectedTable extends Migration
$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('user_id')->references('id')->on('users');
// $table->foreign('source_id')->references('id')->on('qa_user_source');
});
}
@@ -35,6 +37,6 @@ class CreateQAUserAnswerSelectedTable extends Migration
*/
public function down()
{
Schema::dropIfExists('qa_answer_option_selections');
Schema::dropIfExists('qa_user_answer_selected');
}
}
@@ -9,12 +9,14 @@ class QAAnswerOptionsSeeder 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
@@ -23,6 +25,7 @@ class QAAnswerOptionsSeeder extends Seeder
$answerOption->value = "Shipping";
$answerOption->question_number = 10;
$answerOption->next_question_number = 100;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 3 for Question 10
@@ -31,6 +34,7 @@ class QAAnswerOptionsSeeder extends Seeder
$answerOption->value = "Returns";
$answerOption->question_number = 10;
$answerOption->next_question_number = 100;
$answerOption->questionnaire_set_id = 1;
$answerOption->save();
// Option 4 for Question 10
@@ -39,6 +43,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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
@@ -47,6 +52,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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
@@ -55,6 +61,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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
@@ -63,6 +70,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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
@@ -71,6 +79,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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
@@ -78,6 +87,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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
@@ -85,6 +95,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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
@@ -92,6 +103,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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
@@ -99,6 +111,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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
@@ -106,6 +119,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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
@@ -113,6 +127,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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
@@ -120,6 +135,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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();
@@ -128,6 +144,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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
@@ -135,6 +152,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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
@@ -142,6 +160,7 @@ class QAAnswerOptionsSeeder extends Seeder
$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
@@ -150,6 +169,25 @@ class QAAnswerOptionsSeeder extends Seeder
';
$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();
}
}
+60
View File
@@ -16,6 +16,18 @@ class QAQuestionSeeder extends Seeder
'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) {
@@ -155,6 +167,54 @@ class QAQuestionSeeder extends Seeder
'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;
}
@@ -0,0 +1,17 @@
<template>
<div class="row parentContainer">
<div class="col-1">{{ item.questionnaire_set_id }}</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="questions && !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-10" v-else-if="questions[index].question_type === 1" >
<div class="col" >
<validation-wrapper-component :validator="$v.answers.$each[index]" class="col">
<div class="col" v-for="ans in questions[index].question_answers">
<div :class="'col question-answers-' + index">
<div class="btn btn-xs btn-block" :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">
<div class="btn btn-sm btn-primary btn-block b-rad-none" :disabled="!$v.$dirty || !$v.$valid" @click="formTouched = true; submitForm()">Submit</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 }
}
}
},
computed: {
pendingQueue () {
return this.$store.getters.isInCompleteQueue(this.section);
}
},
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-primary');
},
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-primary')[0];
if (btnPrimaryEl) {
btnPrimaryEl.classList.remove('btn-primary');
}
});
},
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': 2, 'text': 'Set 2 - Customer Service Satisfaction Questions'}, {'id': 3, 'text': 'Set 3 - Survey Before conservation with BD ends'}, {'id': 4, 'text': 'Set 4 - After First Order'}]" 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,12 @@
<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">
<generate-feedback-link-form-component></generate-feedback-link-form-component>
</div>
</div>
</template>
<script>
export default {
}
</script>
@@ -0,0 +1,53 @@
<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': []});
console.log(JSON.stringify(response.payload.data[0]));
this.questions = response.payload.data;
}
}
}
</script>
@@ -66,7 +66,7 @@
<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')">{{ data.remarks.length > 0 ? 'Edit' : (question.is_end === 0 ? 'Next' : 'Finish') }}</div>
<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>
@@ -123,7 +123,7 @@
watch: {
pendingQueue(inComplete, oldValue){
if(inComplete){
this.fetchCompany();
this.fetchFirstQuestion();
}
}
},
@@ -131,8 +131,7 @@
this.$store.dispatch('updateListQueue', {'name': this.section});
},
methods: {
fetchCompany(){
this.isLoading = true;
fetchFirstQuestion(){
this.submit(route('api.helpmenu.first.question'), 'get', this.section, false, false);
},
successHandler(response){
@@ -169,7 +168,7 @@
{
this.closeModal();
this.reset();
this.fetchCompany();
this.fetchFirstQuestion();
}
else{
if(this.question.is_end){
@@ -189,7 +188,7 @@
$crisp.push(["do", "message:send", ["text", "Hello there!"]]);
this.closeModal();
this.reset();
this.fetchCompany();
this.fetchFirstQuestion();
}
}
else{
@@ -206,7 +205,6 @@
},
reset() {
this.parameters = null;
this.isLoading = false;
this.answer = '';
this.answerId = 0;
this.files = [];
+5 -1
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(){
@@ -0,0 +1,25 @@
@extends('layouts.base')
@section('content')
<div class="fluid-container h-100">
<div class="row h-100">
<div class="col bg-white no-padding h-100">
<div class="row h-100 align-items-center justify-content-center">
<div class="col h-100">
<div class="page-container">
<div class="page-content-wrapper p-t-50 p-b-50 h-100">
<div class="row no-margin align-items-center justify-content-center h-100">
<div class="col">
<div class="content p-t-0 overflow-hidden">
@yield('inner_content')
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
+39
View File
@@ -0,0 +1,39 @@
@extends('layouts.base_portal')
@section('inner_content')
<div class="row" v-if="$store.getters.isAdmin">
<div class="col">
<admin-feedback-customer-section-component></admin-feedback-customer-section-component>
</div>
</div>
<div class="row" v-if="$store.getters.isAdmin">
<div class="col no-padding">
<div class="row no-margin">
<div class="col bg-master-lightest p-1 p-sm-4">
<div class="row">
<div class="col">
<div class="row">
<div class="col">
<div class="row align-items-center m-t-10 p-t-10 p-b-10 b-t b-grey muted all-caps fs-10">
<div class="col-1">Question Set</div>
<div class="col-2">Question Text</div>
<div class="col-1">Answer</div>
<div class="col-1">Source System</div>
<div class="col-1">Source Marking</div>
<div class="col-2">Source Email</div>
<div class="col-1">Created Date</div>
</div>
</div>
</div>
<list-component section="questionsAnswersSection" :endpoint="route('api.helpmenu.list.questions.answers')" :options="{'per_page': 10, order_by: {column: 'created_at', DESC: true}}">
<template slot="list" slot-scope="{data}">
<question-answer-component :data="data"></question-answer-component>
</template>
</list-component>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@@ -0,0 +1,4 @@
@extends('layouts.base_no_login')
@section('inner_content')
<feedback-customer-section-component token="{{$token}}"></feedback-customer-section-component>
@endsection
File diff suppressed because one or more lines are too long
+2
View File
@@ -24,6 +24,8 @@ Route::group(['middleware' => 'api', 'prefix' => 'v1', 'as' => 'api.'], function
require __DIR__ . '/delivery.php';
require __DIR__ . '/feedback.php';
Route::group(['middleware' => 'valid.token'], function () {
Route::get('/storage/{fileName}/fetch', 'Documents\RenderDocumentController@fileStorageServe')->where(['fileName' => '.*'])->name('storage.document.file');
+8
View File
@@ -0,0 +1,8 @@
<?php
use Illuminate\Support\Facades\Route;
Route::group(['prefix' => 'feedback', 'as' => 'feedback.', 'namespace' => 'HelpMenu'], function () {
Route::post('/list', 'ListHelpMenuQuestionsController@list')->name('list.question');
Route::post('/submit', 'SubmitQAQuestionsController@submit')->name('submit.questions');
});
+2
View File
@@ -5,4 +5,6 @@ use Illuminate\Support\Facades\Route;
Route::group(['prefix' => 'helpmenu', 'as' => 'helpmenu.', 'namespace' => 'HelpMenu'], function () {
Route::get('/question', 'FetchHelpMenuQuestionController@fetch')->name('first.question');
Route::post('/question', 'UpdateHelpMenuNextQuestionController@fetch')->name('next.question');
Route::post('/generate', 'GenerateFeedbackUrlController@generate')->name('feedback.url.generate');
Route::get('/list', 'ListQAController@list')->name('list.questions.answers');
});
+7
View File
@@ -1189,4 +1189,11 @@ Route::get('/duplicate-package-clean-up', function(){
});
Route::get('/feedback/{token}', function ($token) {
return view('pages.feedback.customer', ['token' => $token]);
})->name('feedback.customer');
Route::get('/feedback', function () {
return view('pages.feedback');
})->name('admin.feedback');