Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User dashboard #113

Merged
merged 9 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ php artisan db:seed --env=testing --database=sqlite_testing --class=DatabaseSeed
Then, you can run the tests:

```bash
php artisan test
php artisan test --env=testing
```

## How to debug
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -437,4 +437,23 @@ protected function copyProjectFile(string $filePath): string {

return '/storage/uploads/' . $lastDirName . '/' . $newFile;
}

public function getCrowdSourcingProjectsWithActiveProblems(): Collection {
$language = $this->languageRepository->where(['language_code' => app()->getLocale()]);
$projects = $this->crowdSourcingProjectRepository->getActiveProjectsWithAtLeastOnePublishedProblemWithStatus($language->id);

foreach ($projects as $project) {
// if the model has a "translations" relationship and the first item is not null,
// then set it as the current translation.
// otherwise, set the default translation as the current translation

$project->currentTranslation = $project->translations->first() ?? $project->defaultTranslation;

if ($project->questionnaires->count() > 0) {
$project->latestQuestionnaire = $project->questionnaires->last();
}
}

return $projects;
}
}
43 changes: 28 additions & 15 deletions app/BusinessLogicLayer/UserDashboardManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

namespace App\BusinessLogicLayer;

use App\BusinessLogicLayer\CrowdSourcingProject\CrowdSourcingProjectTranslationManager;
use App\BusinessLogicLayer\CrowdSourcingProject\CrowdSourcingProjectManager;
use App\BusinessLogicLayer\gamification\PlatformWideGamificationBadgesProvider;
use App\BusinessLogicLayer\gamification\QuestionnaireBadgeProvider;
use App\BusinessLogicLayer\lkp\QuestionnaireTypeLkp;
use App\BusinessLogicLayer\questionnaire\QuestionnaireAccessManager;
use App\BusinessLogicLayer\questionnaire\QuestionnaireGoalManager;
use App\Models\CrowdSourcingProject\CrowdSourcingProject;
Expand All @@ -24,27 +25,28 @@ class UserDashboardManager {
protected QuestionnaireBadgeProvider $questionnaireBadgeProvider;
protected QuestionnaireResponseRepository $questionnaireResponseRepository;
protected QuestionnaireAccessManager $questionnaireAccessManager;
protected CrowdSourcingProjectTranslationManager $crowdSourcingProjectTranslationManager;
protected CrowdSourcingProjectManager $crowdSourcingProjectManager;

public function __construct(QuestionnaireRepository $questionnaireRepository,
PlatformWideGamificationBadgesProvider $platformWideGamificationBadgesProvider,
QuestionnaireGoalManager $crowdSourcingProjectGoalManager,
QuestionnaireBadgeProvider $questionnaireBadgeProvider,
QuestionnaireResponseRepository $questionnaireResponseRepository,
QuestionnaireAccessManager $questionnaireAccessManager,
CrowdSourcingProjectTranslationManager $crowdSourcingProjectTranslationManager) {
CrowdSourcingProjectManager $crowdSourcingProjectManager) {
$this->questionnaireRepository = $questionnaireRepository;
$this->platformWideGamificationBadgesProvider = $platformWideGamificationBadgesProvider;
$this->crowdSourcingProjectGoalManager = $crowdSourcingProjectGoalManager;
$this->questionnaireBadgeProvider = $questionnaireBadgeProvider;
$this->questionnaireResponseRepository = $questionnaireResponseRepository;
$this->questionnaireAccessManager = $questionnaireAccessManager;
$this->crowdSourcingProjectTranslationManager = $crowdSourcingProjectTranslationManager;
$this->crowdSourcingProjectManager = $crowdSourcingProjectManager;
}

private function questionnaireShouldBeDisplayedInTheDashboard($questionnaire, $userResponses): bool {
// It's a feedback questionnaire.
if ($questionnaire->type_id == 2) {
// If the questionnaire is a feedback questionnaire, then we should check
// if the user has already answered the main project questionnaire, and has not yet answered the feedback questionnaire.
if ($questionnaire->type_id == QuestionnaireTypeLkp::FEEDBACK_QUESTIONNAIRE) {
// These are supposed to be answered IF and only IF the main project questionnaire is answered
// So we only display them the feedback questionnaire to the dashboard
// IF:
Expand All @@ -54,7 +56,7 @@ private function questionnaireShouldBeDisplayedInTheDashboard($questionnaire, $u
}) == null;
//b) and user has responded to the main project questionnaire
$responseForMainProjectQuestionnaireExists = $userResponses->first(function ($u) use ($questionnaire) {
return $u->questionnaire->type_id == 1 &&
return $u->questionnaire->type_id == QuestionnaireTypeLkp::MAIN_QUESTIONNAIRE &&
$questionnaire->projects->firstWhere('id', $u->project_id) != null;
}) != null;

Expand Down Expand Up @@ -98,8 +100,17 @@ private function evaluateProjectsThatUserCanContributeTo(Questionnaire $q, $user
public function getUserDashboardViewModel(User $user): UserDashboardViewModel {
$userResponses = $this->questionnaireResponseRepository->getQuestionnaireResponsesOfUser($user->id);
$questionnaireIdsUserHasAnsweredTo = $userResponses->pluck('questionnaire_id')->toArray();
$questionnairesToBeDisplayedInTheDashboard = $this->getQuestionnairesForDashboard($user, $userResponses, $questionnaireIdsUserHasAnsweredTo);
$platformWideGamificationBadgesVM = $this->platformWideGamificationBadgesProvider
->getPlatformWideGamificationBadgesListVM($user->id, $questionnaireIdsUserHasAnsweredTo);
$projectsWithActiveProblems = $this->getProjectsWithActiveProblems();

return new UserDashboardViewModel($questionnairesToBeDisplayedInTheDashboard, $projectsWithActiveProblems, $platformWideGamificationBadgesVM, $user);
}

protected function getQuestionnairesForDashboard(User $user, Collection $userResponses, array $questionnaireIdsUserHasAnsweredTo): Collection {
$questionnaires = $this->questionnaireRepository->getActiveQuestionnaires();
$questionnairesToBeDisplayedInTheDashboard = collect([]);
$questionnairesToBeDisplayedInTheDashboard = new Collection;
foreach ($questionnaires as $questionnaire) {
if (!$this->questionnaireShouldBeDisplayedInTheDashboard($questionnaire, $userResponses)) {
continue;
Expand All @@ -108,24 +119,26 @@ public function getUserDashboardViewModel(User $user): UserDashboardViewModel {
$questionnaire->goalVM = $this->crowdSourcingProjectGoalManager
->getQuestionnaireGoalViewModel($questionnaire, $questionnaire->responses_count);

$nextUnlockableBadge = $this->questionnaireBadgeProvider
->getNextUnlockableBadgeToShowForQuestionnaire($questionnaire, $user->id, $questionnaireIdsUserHasAnsweredTo);
$nextBadgeToUnlock = $this->questionnaireBadgeProvider
->getNextBadgeToUnlockForQuestionnaire($questionnaire, $user->id, $questionnaireIdsUserHasAnsweredTo);
$questionnaire->userHasAccessToViewStatisticsPage = $this->questionnaireAccessManager
->userHasAccessToViewQuestionnaireStatisticsPage($user, $questionnaire);

$projectsYouCanContributeTo = $this->evaluateProjectsThatUserCanContributeTo($questionnaire, $userResponses);
$questionnaire->gamificationNextStepVM = new GamificationNextStep(
$projectsYouCanContributeTo,
$nextUnlockableBadge->getNextStepMessage(),
$nextUnlockableBadge->imageFileName,
$nextBadgeToUnlock->getNextStepMessage(),
$nextBadgeToUnlock->imageFileName,
true,
new QuestionnaireSocialShareButtons($questionnaire, $user->id), in_array($questionnaire->id, $questionnaireIdsUserHasAnsweredTo));

$questionnairesToBeDisplayedInTheDashboard->push($questionnaire);
}
$platformWideGamificationBadgesVM = $this->platformWideGamificationBadgesProvider
->getPlatformWideGamificationBadgesListVM($user->id, $questionnaireIdsUserHasAnsweredTo);

return new UserDashboardViewModel($questionnairesToBeDisplayedInTheDashboard, $platformWideGamificationBadgesVM);
return $questionnairesToBeDisplayedInTheDashboard;
}

protected function getProjectsWithActiveProblems(): Collection {
return $this->crowdSourcingProjectManager->getCrowdSourcingProjectsWithActiveProblems();
}
}
34 changes: 6 additions & 28 deletions app/BusinessLogicLayer/gamification/CommunicatorBadge.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,29 @@ public function __construct(int $questionnairesSharedByUser, $userHasAchievedBad
$this->color = '#4CAF50';
$numberOfActionsPerformed = $questionnairesSharedByUser;



parent::__construct(__('badges_messages.communicator_title'),
'communicator.png',
__('badges_messages.gain_badge_by_inviting'),
$numberOfActionsPerformed, $userHasAchievedBadgePlatformWide);
$numberOfActionsPerformed, $userHasAchievedBadgePlatformWide, 10);
}

protected function getBadgeMessageForLevel() {
$word = $this->numberOfActionsPerformed == 1 ? __('badges_messages.time') : __('badges_messages.times');

return __('badges_messages.clicks_on_shared_questionnaires') . ' <b>' . $this->numberOfActionsPerformed . '</b> ' . $word;
protected function getBadgeMessageForLevel(): string {
return __('badges_messages.communicator_badge_points_explanation', ['points' => $this->pointsPerAction]);
}

// protected function getBadgeMessageForLevel() {
// $word = $this->numberOfActionsPerformed == 1 ? __("badges_messages.time") : __("badges_messages.times");
// return __("badges_messages.clicks_on_shared_questionnaires", ["level"=>"<b> $this->numberOfActionsPerformed </b>"]) . $word;
// }

public function getEmailBody() {
public function getEmailBody(): string {
if ($this->level == 1) {
return __('email_messages.unlocked_new_badge');
}

return __('badges_messages.you_are_a_communicator', ['level' => "<b> $this->level </b>"]);
// You are a Level level Communicator! Keep Going!
}

// public function getEmailBody() {
// if($this->level == 1)
// return __("email_messages.unlocked_new_badge");
// return __("badges_messages.become_level_2_communicator", ["level"=>"<b> $this->level </b>"]) ;
// }

public function getNextStepMessage() {
public function getNextStepMessage(): string {
if ($this->userHasAchievedBadgePlatformWide) {
return __('badges_messages.become_a_communicator', ['level'=>'<b> ' . ($this->calculateLevel() + 1) . '</b>']);
return __('badges_messages.become_a_communicator', ['level' => '<b> ' . ($this->calculateLevel() + 1) . '</b>']);
}

return __('badges_messages.gain_communicator_badge');

// public function getNextStepMessage() {
// if($this->userHasAchievedBadgePlatformWide)
// return __("badges_messages.become_level_2_communicator") . " <b>" . ($this->calculateLevel() + 1) . "</b> " . __("email_messages.communicator_title") . "!";
// return __("badges_messages.gain_communicator_badge");
// }
}
}
26 changes: 9 additions & 17 deletions app/BusinessLogicLayer/gamification/ContributorBadge.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,33 @@

class ContributorBadge extends GamificationBadge {
public function __construct(int $allResponses, bool $userHasAchievedBadgePlatformWide) {
$this->badgeID = GamificationBadgeIdsEnum::CONTRUBUTOR_BADGE_ID;
$this->badgeID = GamificationBadgeIdsEnum::CONTRIBUTOR_BADGE_ID;
$this->color = '#3F51B5';
parent::__construct(
__('badges_messages.contributor_title'),
'contributor.png',
__('badges_messages.gain_badge_by_answering'),
__('badges_messages.contributor_badge_points_explanation'),
$allResponses,
$userHasAchievedBadgePlatformWide
$userHasAchievedBadgePlatformWide,
5
);
}

protected function getBadgeMessageForLevel() {
$word = $this->numberOfActionsPerformed == 1 ? __('badges_messages.questionnaire') : __('badges_messages.questionnaires');

return __('badges_messages.you_have_answered', ['count' => "<b> $this->numberOfActionsPerformed </b>"]) . $word;
protected function getBadgeMessageForLevel(): string {
return __('badges_messages.contributor_badge_points_explanation', ['points' => $this->pointsPerAction]);
}

public function getEmailBody() {
public function getEmailBody(): string {
if ($this->level == 1) {
return __('email_messages.unlocked_new_badge');
}

return __('badges_messages.you_are_a_contributor', ['level' => "<b> $this->level </b>"]);
}

// public function getNextStepMessage()
// {
// if ($this->userHasAchievedBadgePlatformWide)
// return __("badges_messages.tell_us_what_you_think") . " <b>" . ($this->calculateLevel() + 1) . "</b> " . __("badges_messages.contributor_title") . "!";
// return __("badges_messages.gain_contributor_badge");
// }

public function getNextStepMessage() {
public function getNextStepMessage(): string {
if ($this->userHasAchievedBadgePlatformWide) {
return __('badges_messages.become_a_contributor', ['level'=>'<b>' . ($this->calculateLevel() + 1) . '</b>']);
return __('badges_messages.become_a_contributor', ['level' => '<b>' . ($this->calculateLevel() + 1) . '</b>']);
}

return __('badges_messages.gain_contributor_badge');
Expand Down
22 changes: 11 additions & 11 deletions app/BusinessLogicLayer/gamification/GamificationBadge.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
namespace App\BusinessLogicLayer\gamification;

abstract class GamificationBadge {
protected $pointsPerAction = 1;
public $badgeID;
public $numberOfActionsPerformed = -1;
public $level = 0;
public $name;
public $messageForLevel;
public $imageFileName;
public $statusMessage;
public $color;
protected $userHasAchievedBadgePlatformWide;
protected int $pointsPerAction = 1;
public string $badgeID;
public int $numberOfActionsPerformed = -1;
public int $level = 0;
public string $name;
public string $messageForLevel;
public string $imageFileName;
public string $statusMessage;
public string $color;
protected bool $userHasAchievedBadgePlatformWide;

public function __construct($name, $imageFileName, $requiredActionMessage,
$numberOfActionsPerformed, $userHasAchievedBadgePlatformWide, $pointsPerAction = 1) {
Expand All @@ -30,7 +30,7 @@ abstract protected function getBadgeMessageForLevel();

abstract public function getEmailBody();

protected function calculateLevel() {
protected function calculateLevel(): int {
return $this->numberOfActionsPerformed * $this->pointsPerAction;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace App\BusinessLogicLayer\gamification;

class GamificationBadgeIdsEnum {
const CONTRUBUTOR_BADGE_ID = 'contributor';
const CONTRIBUTOR_BADGE_ID = 'contributor';
const COMMUNICATOR_BADGE_ID = 'communicator';
const INFLUENCER_BADGE_ID = 'influencer';
const ALL_BADGES_COMPLETED_BADGE_ID = 'allbadger';
Expand Down
31 changes: 9 additions & 22 deletions app/BusinessLogicLayer/gamification/InfluencerBadge.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace App\BusinessLogicLayer\gamification;

class InfluencerBadge extends GamificationBadge {
public $questionnaireReferralsNum;
public int $questionnaireReferralsNum;

public function __construct(int $questionnaireReferralsNum, $userHasAchievedBadgePlatformWide) {
$this->badgeID = GamificationBadgeIdsEnum::INFLUENCER_BADGE_ID;
Expand All @@ -14,45 +14,32 @@ public function __construct(int $questionnaireReferralsNum, $userHasAchievedBadg
'influencer.png',
__('badges_messages.gain_influencer_badge'),
$questionnaireReferralsNum,
$userHasAchievedBadgePlatformWide
$userHasAchievedBadgePlatformWide,
15
);
}

// ??
public function getBadgeMessageForLevel() {
return trans_choice('badges_messages.person_or_people_responded', $this->numberOfActionsPerformed, ['count' => $this->numberOfActionsPerformed]);

// $word = $this->numberOfActionsPerformed == 1 ? __("badges_messages.person") : __("badges_messages.people");
// return $this->numberOfActionsPerformed . ' ' . $word . __("badges_messages.responded_to_call");
protected function getBadgeMessageForLevel(): string {
return __('badges_messages.influencer_badge_points_explanation', ['points' => $this->pointsPerAction]);
}

public function getEmailBody() {
public function getEmailBody(): string {
if ($this->level == 1) {
return __('email_messages.unlocked_new_badge');
}

return __('badges_messages.you_are_an_influencer', ['level' => "<b> $this->level </b>"]);
}

// ??
public function getNextStepMessage() {
public function getNextStepMessage(): string {
if (!$this->questionnaireReferralsNum) {
$title = __('badges_messages.zero_people_responded_to_call');
} elseif ($this->questionnaireReferralsNum < 2) {
// $peopleStr = $this->questionnaireReferralsNum == 1 ? __("badges_messages.person_has_responded") : __("badges_messages.people_have_responded");
// $title = __("badges_messages.good_job") . $this->questionnaireReferralsNum . $peopleStr . __("badges_messages.people_responded_to_call");
$title = trans_choice('badges_messages.good_job', $this->questionnaireReferralsNum, ['count' => $this->questionnaireReferralsNum]);
$title = __('badges_messages.good_job', $this->questionnaireReferralsNum, ['count' => $this->questionnaireReferralsNum]);
} else {
// $peopleStr = $this->questionnaireReferralsNum == 1 ? __("badges_messages.person_has_responded") : __("badges_messages.people_have_responded");
// $title = __("badges_messages.true_influencer") . $this->questionnaireReferralsNum . $peopleStr . __("badges_messages.people_responded_to_call_2");
$title = trans_choice('badges_messages.true_influencer', $this->questionnaireReferralsNum, ['count' => $this->questionnaireReferralsNum]);
$title = __('badges_messages.true_influencer', $this->questionnaireReferralsNum, ['count' => $this->questionnaireReferralsNum]);
}

// if ($this->userHasAchievedBadgePlatformWide)
// $title .= __("badges_messages.you_are_close") . " <b>" . ($this->calculateLevel() + 1) . "</b> " . __("badges_messages.influencer_title") . "!";
// return $title;
// }

if ($this->userHasAchievedBadgePlatformWide) {
$title .= __('badges_messages.become_an_influencer', ['level' => '<b> ' . ($this->calculateLevel() + 1) . ' </b>']);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function __construct(QuestionnaireRepository $questionnaireRepository,
$this->platformWideGamificationBadgesProvider = $platformWideGamificationBadgesProvider;
}

public function getNextUnlockableBadgeToShowForQuestionnaire(Questionnaire $questionnaire, int $userId, array $questionnaireIdsUserHasAnsweredTo): GamificationBadge {
public function getNextBadgeToUnlockForQuestionnaire(Questionnaire $questionnaire, int $userId, array $questionnaireIdsUserHasAnsweredTo): GamificationBadge {
if (!$this->userHasAchievedContributorBadgeForQuestionnaire($questionnaire->id, $questionnaireIdsUserHasAnsweredTo)) {
return new ContributorBadge(count($questionnaireIdsUserHasAnsweredTo), count($questionnaireIdsUserHasAnsweredTo));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
class QuestionnaireGoalManager {
public function getQuestionnaireGoalViewModel(Questionnaire $questionnaire, int $responses_count): QuestionnaireProjectGoal {
$responsesNeededToReachGoal = $questionnaire->goal - $responses_count;
if ($responsesNeededToReachGoal < 0) {
$responsesNeededToReachGoal = 0;
}
if ($questionnaire->goal == 0) {
$targetAchievedPercentage = 0;
} else {
Expand Down
Loading
Loading