Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 1724
0.00% covered (danger)
0.00%
0 / 82
CRAP
0.00% covered (danger)
0.00%
0 / 1
AdminAccountCenterDashboardController
0.00% covered (danger)
0.00%
0 / 1724
0.00% covered (danger)
0.00%
0 / 82
99540
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 _buildUsersResponse
0.00% covered (danger)
0.00%
0 / 53
0.00% covered (danger)
0.00%
0 / 1
210
 _make_line_chart_data
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
12
 _make_line_chart_data_for_counts
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
12
 _make_line_chart_data_extension
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
20
 _assign_plan
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 1
552
 filterUsersByAdmin
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 filterUsersByGroupIds
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
20
 users
0.00% covered (danger)
0.00%
0 / 82
0.00% covered (danger)
0.00%
0 / 1
812
 groups
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
30
 search_users
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
6
 update_user
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 update_invite
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
12
 create_user_manually
0.00% covered (danger)
0.00%
0 / 117
0.00% covered (danger)
0.00%
0 / 1
182
 resend_temporary_password
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
6
 create_user_by_csv
0.00% covered (danger)
0.00%
0 / 64
0.00% covered (danger)
0.00%
0 / 1
30
 deactivate_user
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 deactivate_invited_user
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
20
 delete_user
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 reset_password
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 reset_invitation_password
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 resend_user_invitation
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
6
 resend_invitations
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 1
42
 move_group
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 move_group_invite
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 assign_role
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 1
210
 deactivate_user_bulk
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 _reactive_users
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
 _assign_plans_to_users
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
20
 reactivate_user_bulk
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
20
 delete_user_bulk
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
56
 reset_password_bulk
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
20
 resend_user_invitation_bulk
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
30
 move_group_bulk
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 group_exists
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
 create_group
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
2
 update_group
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 delete_group
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
56
 add_users_to_group
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 add_subgroup_to_group
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
2
 export_csv
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 import_csv
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 reporting_licenses
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
20
 reporting_roi_spotlight
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 reporting_productivity_spotlight
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 reporting_total_characters_typed_spotlight
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 reporting_total_fly_grammar_spotlight
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 reporting_total_fly_cuts_spotlight
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 reporting_flymsg_coach_level
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 reporting_flycuts_created
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
20
 reporting_flycuts_created_top_users
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 reporting_flyplates_added
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
20
 reporting_flyplates_added_top_users
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 reporting_sentence_rewrite_ai
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
20
 reporting_sentence_rewrite_ai_used_top_users
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 reporting_paragraph_rewrite_ai
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
20
 reporting_paragraph_rewrite_ai_used_top_users
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 reporting_flyengage_ai
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
20
 reporting_flyengage_ai_used_top_users
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 reporting_flypost_ai
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
20
 reporting_flypost_ai_used_top_users
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getTop5
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
30
 reporting_characters_typed_saving_top_users
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 reporting_fly_grammar_top_users
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 reporting_fly_cuts_top_users
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 reporting_fly_grammar_accepted_top_users
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 reporting_fly_grammar_autocorrect_top_users
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 reporting_fly_grammar_autocomplete_top_users
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 reporting_time_saving_top_users
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 reporting_cost_saving_top_users
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 reporting_active_users
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
20
 reporting_extension_usage
0.00% covered (danger)
0.00%
0 / 68
0.00% covered (danger)
0.00%
0 / 1
156
 reporting_user_details
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
30
 reporting_get_columns
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
6
 reporting_save_columns
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 1
56
 export_user_details_csv
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
6
 reset_invited_user_password
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 1
30
 export_csv_report
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 export_csv_report_overview
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 export_csv_report_usage
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 remove_users_from_group
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 user_info
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Http\Controllers\v1\AdminPortal;
4
5use App\Actions\AccountCenter\Reporting\FmsCoachLevelSpotlightAction;
6use App\Actions\AccountCenter\Reporting\ProductivitySpotlightAction;
7use App\Actions\AccountCenter\Reporting\RoiSpotlightAction;
8use App\Actions\AccountCenter\Reporting\TotalCharactersTypedSpotlightAction;
9use App\Actions\AccountCenter\Reporting\TotalFlyCutsSpotlightAction;
10use App\Actions\AccountCenter\Reporting\TotalFlyGrammarSpotlightAction;
11use App\Actions\Users\SendUserInvitationAction;
12use App\Actions\Users\UpdateUserAction;
13use App\DTO\AccountCenter\Reporting\ReportingRequestDTO;
14use App\DTO\User\SendUserInvitationDTO;
15use App\DTO\User\UpdateUserDTO;
16use App\Events\User\Registered;
17use App\Exceptions\ExpectedException;
18use App\Exports\UsersExport;
19use App\Exports\UsersReportExport;
20use App\Exports\UsersReportOverviewExport;
21use App\Exports\UsersReportUsageExport;
22use App\Helpers\Constants;
23use App\Helpers\FlyMSGLogger;
24use App\Http\Controllers\Controller;
25use App\Http\Models\Admin\AdminUserInvitation;
26use App\Http\Models\Admin\Company;
27use App\Http\Models\Admin\CompanyGroup;
28use App\Http\Models\Admin\CompanyLicenses;
29use App\Http\Models\Admin\UserDetailsColumnSetting;
30use App\Http\Models\Auth\Role;
31use App\Http\Models\Auth\User;
32use App\Http\Models\Auth\UserRole;
33use App\Http\Models\HubspotProperties;
34use App\Http\Models\Plans;
35use App\Http\Models\SalesProTeamManager;
36use App\Http\Resources\AdminCenterCompanyGroupResource;
37use App\Http\Resources\AdminCenterUserResource;
38use App\Http\Resources\UserDetailsReportingResource;
39use App\Http\Resources\UserDetailsReportResource;
40use App\Http\Services\Admin\Groups\AdminGroupsService;
41use App\Http\Services\Admin\Reports\AccountCenterReportingService;
42use App\Http\Services\Admin\Reports\FindUsersOverviewFilter;
43use App\Http\Services\Admin\Users\AdminUsersService;
44use App\Http\Services\InstancyServiceV2;
45use App\Imports\UsersImport;
46use App\Jobs\Emails\AddNewUserReminder;
47use App\Mail\AdminCenterAddExistingUser;
48use App\Mail\AdminCenterAddNewUser;
49use App\Mail\AdminCenterAddNewUserByEmail;
50use App\Mail\InvitationToJoinFlymsgEmail;
51use App\Mail\SendResetPasswordRequestedEmail;
52use App\Traits\AccountCenter\Reporting\ChartTrait;
53use Carbon\Carbon;
54use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
55use Illuminate\Http\JsonResponse;
56use Illuminate\Http\Request;
57use Illuminate\Support\Facades\Hash;
58use Illuminate\Support\Facades\Password;
59use Illuminate\Support\Str;
60use Illuminate\Validation\Rule;
61use MongoDB\BSON\UTCDateTime;
62use App\Jobs\Emails\ReactivateUserNotification;
63use App\Jobs\Emails\AddNewUserNotification;
64use App\Events\DeleteInstancyGroup;
65use App\Http\Models\FlyMsgUserDailyUsage;
66use App\Services\Email\EmailService;
67
68class AdminAccountCenterDashboardController extends Controller
69{
70    use SendsPasswordResetEmails;
71    use ChartTrait;
72
73    public function __construct(
74        private AdminUsersService $adminUsersService,
75        private AdminGroupsService $adminGroupsService,
76        private AccountCenterReportingService $accountCenterReportingService,
77        private EmailService $emailService
78    ) {}
79
80    private function _buildUsersResponse($model, $group_name, $subgroup_name, $is_invite, $company)
81    {
82        $identifier = "freemium";
83        if ($model->subscription("main") && $model->subscription("main")->valid() && $model->subscription("main")->plan) {
84            $identifier = $model->subscription("main")->plan->identifier;
85        } elseif ($model->subscription("invitation")) {
86            $identifier = $model->subscription("invitation")->identifier;
87        } elseif ($model->status == "Invited") {
88            $invitation = AdminUserInvitation::where("email", $model->email)->first();
89            if (filled($invitation?->plan_id)) {
90                $plan = Plans::find($invitation->plan_id);
91                $identifier = $plan?->identifier ?? "freemium";
92            }
93        }
94
95        $plan_name = $this->parseSubscriptionPlanName($identifier);
96
97        $statusDate = match (true) {
98            !is_null($model->deactivated_at)
99                ? ($model->deactivated_at instanceof \Carbon\Carbon
100                    ? $model->deactivated_at->toFormattedDateString()
101                    : \Carbon\Carbon::parse($model->deactivated_at)->toFormattedDateString())
102                : null,
103            !is_null($model->activation_date) => Carbon::parse($model->activation_date)->toFormattedDateString(),
104            !is_null($model->created_at) => $model->created_at->toFormattedDateString(),
105            default => null,
106        };
107
108        $status = $model->status ?? "Active";
109
110        $user_properties = [
111            'id' => $model->id,
112            'avatar' => $model->avatar,
113            'first_name' => $model->first_name,
114            'last_name' => $model->last_name,
115            'email' => $model->email,
116            'role' => role($model->role),
117            'group' => $group_name,
118            'sub_group' => $subgroup_name,
119            'group_subgroup' => $subgroup_name != "Not Assigned" ? $subgroup_name : $group_name,
120            "licenseType" => $plan_name,
121            "status" => $status,
122            "invitation_link" => $model->getInvitationLinkForAdminPortal(),
123            "created_at" => $model->created_at ?? $model->updated_at,
124            "user_id" => $model->id,
125            "group_id" => $model->company_group_id,
126            "group_subgroup_id" => $model->company_group_id,
127            "statusDate" => $statusDate,
128            "is_invite" => $is_invite,
129            "company_slug" => $company->slug,
130        ];
131
132        if ($user_properties["status"] == "Invited") {
133            $user_properties["invitation_link"] = $model->getInvitationLinkForAdminPortal();
134            $invitation = AdminUserInvitation::where("email", $model->email)->first();
135            if ($invitation) {
136                $user_properties["statusDate"] = $invitation?->updated_at?->toFormattedDateString();
137
138                if (filled($invitation->role_name)) {
139                    $user_properties["role"] = $invitation->role_name;
140                }
141            }
142        }
143
144        if ($model->sales_pro_team_manager) {
145            $user_properties["groups_admin"] = $model->sales_pro_team_manager?->company_group_ids;
146        }
147
148        return $user_properties;
149    }
150
151    private function _make_line_chart_data($flycut_usages, $months)
152    {
153        // Initialize the line chart data array
154        $line_chart_data = [];
155        $current_date = Carbon::now();
156        for ($i = 0; $i < $months; $i++) {
157            $month_year = $current_date->subMonth()->format('M Y');
158            $line_chart_data[$month_year] = [
159                'month_year' => $month_year,
160                'flycuts_used' => 0,
161                'characters_typed' => round(0, 2),
162                'time_saved' => round(0, 2),
163                'cost_saved' => round(0, 2),
164            ];
165        }
166
167        // Aggregate the data by month
168        $aggregated_data = $flycut_usages->groupBy(function ($date) {
169            return Carbon::parse($date->created_at)->format('M Y');
170        });
171
172        // Process the aggregated data
173        foreach ($aggregated_data as $month_year => $usages) {
174            $month = Carbon::parse($usages->first()->created_at)->format('M Y');
175
176            $flycuts_used = $usages->count();
177            $characters_typed = $usages->sum('characters_typed');
178            $time_saved = $usages->sum('time_saved');
179            $cost_saved = $usages->sum('cost_saved');
180
181            $line_chart_data[$month] = [
182                'month_year' => $month_year,
183                'flycuts_used' => $flycuts_used,
184                'characters_typed' => round($characters_typed, 2),
185                'time_saved' => round($time_saved, 2),
186                'cost_saved' => round($cost_saved, 2),
187            ];
188        }
189
190        // Convert month-year strings to DateTime objects and sort by date
191        uksort($line_chart_data, function ($a, $b) {
192            return strtotime($a) - strtotime($b);
193        });
194
195        return $line_chart_data;
196    }
197
198    private function _make_line_chart_data_for_counts($flycuts, $months)
199    {
200        // Initialize an array with 12 months set to 0
201        $line_chart_data = [];
202        $current_date = Carbon::now();
203        for ($i = 0; $i < $months; $i++) {
204            $month_year = $current_date->subMonth()->format('M Y');
205            $line_chart_data[$month_year] = ['count' => 0];
206        }
207
208        // Reset the current date to now
209        $current_date = Carbon::now();
210
211        // Aggregate the data by month
212        $aggregated_data = $flycuts->groupBy(function ($date) {
213            return Carbon::parse($date->created_at)->format('Y-m');
214        });
215
216        // Process the aggregated data and populate the line chart data array
217        foreach ($aggregated_data as $month_year => $usages) {
218            $month = Carbon::parse($usages->first()->created_at)->format('M Y');
219            $flycuts_used = $usages->count();
220            $line_chart_data[$month] = ['count' => $flycuts_used];
221        }
222
223        // Ensure the data is sorted by date keys
224        uksort($line_chart_data, function ($a, $b) {
225            return strtotime($a) - strtotime($b);
226        });
227
228        return $line_chart_data;
229    }
230
231    private function _make_line_chart_data_extension($extensions_data, $months, $start_date)
232    {
233        $line_chart_data = [];
234        for ($i = 0; $i <= $months; $i++) {
235            $month_year = $start_date->copy()->addMonths($i)->format('M Y');
236            $line_chart_data[$month_year] = [
237                'edge_installed' => 0,
238                'chrome_installed' => 0,
239                'uninstalls' => 0,
240            ];
241        }
242
243        $aggregated_data = $extensions_data->groupBy(function ($data) {
244            return Carbon::parse($data->created_at)->format('M Y');
245        });
246
247        foreach ($aggregated_data as $month_year => $usages) {
248            $edge_count = $usages->where('flymsg_edge_extension_installed', 'Yes')->count();
249            $chrome_count = $usages->where('flymsg_chrome_extension_installed', 'Yes')->count();
250            $uninstall_count = $usages->where('flymsg_chrome_extension_uninstalled', 'Yes')->count() + $usages->where('flymsg_edge_extension_uninstalled', 'Yes')->count();
251
252            if (isset($line_chart_data[$month_year])) {
253                $line_chart_data[$month_year]['edge_installed'] += $edge_count;
254                $line_chart_data[$month_year]['chrome_installed'] += $chrome_count;
255                $line_chart_data[$month_year]['uninstalls'] += $uninstall_count;
256            }
257        }
258
259        uksort($line_chart_data, function ($a, $b) {
260            return strtotime($a) - strtotime($b);
261        });
262
263        return $line_chart_data;
264    }
265
266    private function _assign_plan($user, $plan, $selected_plan, $email, $is_reactivate = false)
267    {
268        if ($plan) {
269            $company_license = CompanyLicenses::where('company_id', $user->company_id)
270                ->active()
271                ->first();
272            if (!$company_license) {
273                throw new ExpectedException("Failed to assign $selected_plan. The company doesn't have any active license.");
274            }
275
276            switch ($selected_plan) {
277                case 'Starter':
278                case 'Starter Yearly':
279                    if ($company_license->total_starter_license_remaining < 1) {
280                        // throw new ExpectedException("Failed to assign $selected_plan. License plan unavailable");
281                    }
282                    $company_license->decrement('total_starter_license_remaining');
283                    break;
284                case 'Growth':
285                case 'Growth Yearly':
286                    if ($company_license->total_growth_license_remaining < 1) {
287                        // throw new ExpectedException("Failed to assign $selected_plan. License plan unavailable");
288                    }
289                    $company_license->decrement('total_growth_license_remaining');
290                    break;
291                case 'Sales Pro':
292                case 'FlyMSG.io Sales Pro - YR Plan':
293                    if ($company_license->total_sales_pro_license_remaining < 1) {
294                        // throw new ExpectedException("Failed to assign $selected_plan. License plan unavailable");
295                    }
296                    $company_license->decrement('total_sales_pro_license_remaining');
297                    break;
298                case 'Sales Pro Teams':
299                case 'Pro Plan Teams - ENT':
300                    if ($company_license->total_sales_pro_teams_license_remaining < 1) {
301                        // throw new ExpectedException("Failed to assign $selected_plan. License plan unavailable");
302                    }
303                    $company_license->decrement('total_sales_pro_teams_license_remaining');
304                    break;
305            }
306
307            if ($user instanceof User) {
308                if ($user->subscribed('main')) {
309                    if ($is_reactivate) {
310                        $user->subscription('main')->markAsCancelledOnlyInDB();
311                    } else {
312                        $user->subscription('main')->cancel();
313                    }
314                } else {
315                    $subscription = $user->subscriptions()->latest()->first();
316                    if ($subscription) {
317                        $subscription->update([
318                            'stripe_status' => 'canceled',
319                            'ends_at' => Carbon::now()->toDateTimeString(),
320                        ]);
321                    }
322                }
323
324                $end_date = $company_license->contract_end_date;
325
326                $user->subscriptions()->create([
327                    'name' => 'main',
328                    'stripe_status' => 'active',
329                    'stripe_plan' => $plan->stripe_id,
330                    'quantity' => "1",
331                    'ends_at' => $end_date,
332                    'starts_at' => Carbon::now()->toDateTimeString(),
333                ]);
334
335                if (in_array($selected_plan, ["Sales Pro", "Sales Pro Teams"])) {
336                    try {
337                        $group = CompanyGroup::find($user->company_group_id);
338                        $company = Company::find($user->company_id);
339
340                        $groupId = false;
341                        if ($company) {
342                            $groupId = $company->instancy_id;
343                        } elseif ($group) {
344                            $groupId = $group->instancy_id;
345                        }
346
347                        (new InstancyServiceV2)->createInstancyUser($email, $groupId);
348                    } catch (\Throwable $th) {
349                        FlyMSGLogger::logError(__METHOD__, $th);
350                    }
351                }
352            }
353        }
354    }
355
356    private function filterUsersByAdmin($query, $role, $company_id, $admin_group_ids)
357    {
358        return match ($role) {
359            Role::GLOBAL_ADMIN, Role::VENGRESO_ADMIN => $query->where("company_id", "=", $company_id),
360            default => $query->whereIn("company_group_id", $admin_group_ids),
361        };
362    }
363
364    private function filterUsersByGroupIds($query, $role, $group_ids, $company_id, $admin_group_ids)
365    {
366        if ($role == Role::GLOBAL_ADMIN || $role == Role::VENGRESO_ADMIN) {
367            return $query->where("company_id", "=", $company_id);
368        } elseif (count($group_ids) == 0) {
369            return $query->whereIn("company_group_id", $admin_group_ids);
370        }
371
372        return $query;
373    }
374
375    public function users(Request $request)
376    {
377        // Deactivated users are soft deleted users
378        $only_deactivated = $request->has('deactivated') && $request->deactivated == "true";
379
380        $admin = auth()->user();
381        $roles = $admin->role;
382        $role = role($roles);
383        $company_id = $request->company_id;
384        $admin_group_ids = $request->admin_group_ids;
385
386        $company = Company::find($company_id);
387
388        $users = User::select([
389            "id",
390            "avatar",
391            "first_name",
392            "last_name",
393            "email",
394            "role",
395            "company_id",
396            "company_group_id",
397            "sales_pro_team_manager_id",
398            "status",
399            "created_at",
400            'updated_at',
401            "deleted_at",
402            'activation_date',
403            "deactivated_at",
404        ]);
405
406        $users = $this->filterUsersByAdmin($users, $role, $company_id, $admin_group_ids);
407
408        if ($only_deactivated) {
409            $users = $users->whereNotNull('deactivated_at');
410        } else {
411            $users = $users->whereNull('deactivated_at');
412        }
413
414        $users = $users->latest();
415        $users = $users->get();
416
417        // TODO MA. Please find a better way to do this and
418        // avoid this loop.
419        $response_builder = [];
420        foreach ($users as $user) {
421            $group_name = $user->company_group ? $user->company_group->name : "Not Assigned";
422            $subgroup_name = $user->company_group ? $user->company_group->name : "Not Assigned";
423
424            if ($user->company_group && $user->company_group->parent_id) {
425                $group_name = $user->company_group->parent ? $user->company_group->parent->name : "Not Assigned";
426            }
427
428            if ($user->company_group && !$user->company_group->parent_id) {
429                $subgroup_name = "Not Assigned";
430            }
431
432            $user_properties = $this->_buildUsersResponse($user, $group_name, $subgroup_name, false, $company);
433
434            $response_builder[] = $user_properties;
435        }
436
437
438
439        if (!$only_deactivated) {
440            $invitations = $this->filterUsersByAdmin(
441                AdminUserInvitation::where("company_id", $company_id)
442                    ->whereNull('deactivated_at')
443                    ->whereNotIn("email", $users->pluck("email")),
444                $role,
445                $company_id,
446                $admin_group_ids
447            )->get();
448
449            foreach ($invitations as $invitation) {
450                $group_name = $invitation->company_group ? $invitation->company_group->name : "Not Assigned";
451                $subgroup_name = $invitation->company_group ? $invitation->company_group->name : "Not Assigned";
452
453                if ($invitation->company_group && $invitation->company_group->parent_id) {
454                    $group_name = $invitation->company_group->parent ? $invitation->company_group->parent->name : "Not Assigned";
455                }
456
457                if ($invitation->company_group && !$invitation->company_group->parent_id) {
458                    $subgroup_name = "Not Assigned";
459                }
460
461                $user_properties = $this->_buildUsersResponse($invitation, $group_name, $subgroup_name, true, $company);
462
463                $response_builder[] = $user_properties;
464            }
465        } else {
466
467            $invitations = $this->filterUsersByAdmin(
468                AdminUserInvitation::where("company_id", $company_id)
469                    ->whereNotNull('deactivated_at')
470                    ->whereNotIn("email", $users->pluck("email")),
471                $role,
472                $company_id,
473                $admin_group_ids
474            )->get();
475
476            foreach ($invitations as $invitation) {
477                $group_name = $invitation->company_group ? $invitation->company_group->name : "Not Assigned";
478                $subgroup_name = $invitation->company_group ? $invitation->company_group->name : "Not Assigned";
479
480                if ($invitation->company_group && $invitation->company_group->parent_id) {
481                    $group_name = $invitation->company_group->parent ? $invitation->company_group->parent->name : "Not Assigned";
482                }
483
484                if ($invitation->company_group && !$invitation->company_group->parent_id) {
485                    $subgroup_name = "Not Assigned";
486                }
487
488                $user_properties = $this->_buildUsersResponse($invitation, $group_name, $subgroup_name, true, $company);
489
490                $response_builder[] = $user_properties;
491            }
492        }
493
494        return response()->json(
495            data: [
496                'success' => true,
497                'users' => $response_builder,
498            ],
499            status: 200
500        );
501    }
502
503    public function groups(Request $request)
504    {
505        $user = auth()->user();
506        $roles = $user->role;
507        $role = role($roles);
508        $show_not_assigned = $request->show_not_assigned === "true";
509        $company_id = $request->company_id;
510        $admin_group_ids = $request->admin_group_ids;
511
512        $groups = CompanyGroup::select(["id", "name", "company_id", "parent_id"])
513            ->whereNull("parent_id")
514            ->where("company_id", $company_id)
515            ->with(["users", "subgroups"]);
516
517        if ($role == Role::GLOBAL_ADMIN || $role == Role::VENGRESO_ADMIN) {
518            $groups = $groups->get();
519        } else {
520            $sales_pro_manager = SalesProTeamManager::where("email", $user->email)->first();
521            if (!$sales_pro_manager) {
522                throw new ExpectedException("User role is not setup to handle [GroupAdmin/ReportingAdmin] roles well. We have been notified about it!");
523            }
524            $groups = $groups->whereIn("_id", $admin_group_ids)->get();
525        }
526
527        if ($show_not_assigned) {
528            $notAssignedGroup = new CompanyGroup();
529            $notAssignedGroup->name = "Not Assigned";
530            $notAssignedGroup->slug = "not-assigned";
531            $notAssignedGroup->id = -1;
532            $groups->push($notAssignedGroup);
533        }
534
535        $transformer = AdminCenterCompanyGroupResource::collection($groups);
536
537        return response()->json(data: [
538            'success' => true,
539            'groups' => $transformer->toArray($request),
540        ], status: 200);
541    }
542
543    public function search_users(Request $request)
544    {
545        $user = auth()->user();
546        $roles = $user->role;
547        $role = role($roles);
548        $search_term = $request->search_term;
549        $company_id = $request->company_id;
550        $admin_group_ids = $request->admin_group_ids;
551
552        $users = User::select([
553            "id",
554            "first_name",
555            "last_name",
556            "email",
557            "role",
558            "company_id",
559            "company_group_id",
560            "sales_pro_team_manager_id",
561            "deactivated_at",
562            "status",
563            "created_at",
564            "avatar"
565        ]);
566
567        if ($search_term) {
568            $users = $users->where("email", "like", "%$search_term%")
569                ->orWhere("first_name", "like", "%$search_term%")
570                ->orWhere("last_name", "like", "%$search_term%");
571        }
572
573        $users = $this->filterUsersByAdmin($users, $role, $company_id, $admin_group_ids);
574
575        $users = $users->get();
576
577        $users_response = AdminCenterUserResource::collection($users);
578        return response()->json(data: [
579            'success' => true,
580            'users' => $users_response->toArray($request),
581        ], status: 200);
582    }
583
584    public function update_user(Request $request, $slug, User $user, UpdateUserAction $updateUserAction)
585    {
586        $userDTO = new UpdateUserDTO(
587            email: strtolower($request->email),
588            firstName: $request->first_name,
589            lastName: $request->last_name,
590        );
591
592        $updateUserAction->execute($user, $userDTO);
593
594        return response()->json(data: [
595            'success' => true,
596            'user' => new AdminCenterUserResource($user)
597        ], status: 200);
598    }
599
600    public function update_invite(Request $request, $slug, AdminUserInvitation $invite)
601    {
602        $inputData = $request->all();
603        $newEmail = strtolower($inputData['email']);
604        $sendEmail = strtolower($invite->email) !== $newEmail;
605        $inputData['email'] = $newEmail;
606
607        if (!$invite->update($inputData)) {
608            throw new ExpectedException("Failed to update the users data. Please try again later.");
609        }
610
611        if ($sendEmail) {
612            $this->emailService->send(
613                $invite->email,
614                new AdminCenterAddNewUserByEmail(
615                    email: $invite->email
616                ),
617                'cac_add_user_by_email'
618            );
619        }
620
621        return response()->json(data: [
622            'success' => true,
623            'user' => new AdminCenterUserResource($invite)
624        ], status: 200);
625    }
626
627    public function create_user_manually(Request $request)
628    {
629        $existing_user = false;
630
631        $validated_data = $request->validate([
632            "first_name" => "required|string",
633            "last_name" => "required|string",
634            "email" => "required|email|max:255",
635            "selected_plan" => ["required", "string", Rule::in(["Starter", "Growth", "Sales Pro", "Sales Pro Teams"])]
636        ]);
637
638        $admin = auth()->user();
639        $company_id = $request->company_id;
640
641        $email = strtolower($request->email);
642        $password = Str::password(16);
643        $hashed_password = bcrypt($password);
644        $selected_plan = $request->selected_plan;
645
646        $user = User::where("email", $email)
647            ->where("company_id", $company_id)
648            ->first();
649        if ($user) {
650            throw new ExpectedException("The user with email {$email} already exists in your Organization.");
651        }
652
653        $planTitle = "";
654        if ($selected_plan == "Sales Pro") {
655            $planTitle = "FlyMSG.io Sales Pro - YR Plan";
656        } else if ($selected_plan == "Growth") {
657            $planTitle = "Growth Yearly";
658        } else if ($selected_plan == "Starter") {
659            $planTitle = "Starter Yearly";
660        } else if ($selected_plan == "Sales Pro Teams") {
661            $planTitle = "Pro Plan Teams - ENT";
662        }
663
664        $plan = Plans::firstWhere("title", $planTitle);
665
666        $password_expiry = Carbon::now()->addDays(7);
667
668        $user = User::where("email", $email)
669            ->first();
670        if ($user) {
671            $existing_user = true;
672
673            $user->company_id = $company_id;
674            $user->invited_to_company = true;
675            $user->invited_to_company_by_admin = $admin->email;
676            $user->status = "Invited";
677            $user->save();
678
679            $this->emailService->send(
680                $email,
681                new AdminCenterAddExistingUser(
682                    admin_email: $admin->email,
683                    email: $user->email,
684                    company: $admin->company->name,
685                ),
686                'cac_add_existent_user'
687            );
688        } else {
689            $existing_user = false;
690
691            $user = new User();
692            $user->fill($validated_data);
693            $user->status = "Invited";
694            $user->email = $email;
695            $user->password = $hashed_password;
696            $user->company_id = $company_id;
697            $user->temp_password_expiry = $password_expiry->toDateTimeString();
698            $user->temp_password = $hashed_password;
699            $user->email_verified_at = new UTCDateTime(now()->getTimestamp() * 1000);
700            $user->onboardingv2_presented = true;
701
702            $user->save();
703        }
704
705        $password_expiry = $password_expiry->format("m/d/Y") . " at " . $password_expiry->format("h:i A");
706
707        $data = [
708            "email" => $email,
709            "company_id" =>  $company_id,
710            "company_group_id" => $request->group_id,
711            "company_subgroup_id" => $request->subgroup_id,
712            "temp_password_expiry" => $user->temp_password_expiry,
713            "temp_password" => $hashed_password,
714            "password" => $hashed_password,
715            "admin_email" => $admin->email
716        ];
717
718        $invitation = AdminUserInvitation::updateOrCreate(['email' => $email], $data);
719
720        // if there is plan, assign it
721        // if there is a plan, reduce the count after assignement in the company license
722        if ($plan) {
723            $invitation->plan = $plan;
724            $invitation->plan_id = $plan->id;
725            $invitation->save();
726            if (!$existing_user) {
727                $this->_assign_plan($user, $plan, $selected_plan, $email);
728            }
729        }
730
731        $data = [
732            "email" => $user->email,
733            "first_name" => $user->first_name,
734            "last_name" => $user->last_name,
735        ];
736
737        if (!$existing_user) {
738            Registered::dispatch($user, $data);
739
740            $this->emailService->send(
741                $email,
742                new AdminCenterAddNewUser(
743                    email: $email,
744                    password: $password,
745                    inviter: $admin->email,
746                    password_expiry: $password_expiry,
747                ),
748                'cac_add_new_user_manually'
749            );
750
751            $companyName = $admin->company->name;
752            $companyEmail = $admin->email;
753
754            if ($company_id) {
755                $company = Company::find($user->company_id);
756                $companyLicense = CompanyLicenses::where('company_id', $company->id)->first();
757                $community = $companyLicense->business_pro_enterprise_plus ?? [];
758                $isPro = in_array('yes_dedicated', $community) || in_array('yes_community', $community);
759
760                if ($isPro) {
761                    AddNewUserNotification::dispatch($data['email'], $companyEmail, $companyName, $this->emailService)->delay(now()->addSeconds(2));
762                }
763            }
764
765            $addnewUserEmailJob = (new AddNewUserReminder(
766                $email,
767                $password,
768                $admin->email,
769                $password_expiry,
770                $this->emailService
771            ))->delay(now()->addHours(48));
772
773            $job = app(\Illuminate\Contracts\Bus\Dispatcher::class)->dispatch($addnewUserEmailJob);
774
775            $invitation->reminder_job_id = $job;
776            $invitation->save();
777        }
778
779        return response()->json(data: [
780            'success' => true,
781            'user' => (new AdminCenterUserResource($user))->setPlan($plan),
782        ], status: 200);
783    }
784
785    public function resend_temporary_password(Request $request)
786    {
787        $validated_data = $request->validate([
788            "email" => "required|email|max:255",
789        ]);
790
791        $email = strtolower($validated_data["email"]);
792
793        $user = User::where("email", $email)
794            ->first();
795
796        $invitation = AdminUserInvitation::where("email", $email)
797            ->first();
798
799        // if ($user && $invitation) {
800        //     throw new ExpectedException("The user with email {$email} already exists in your company.");
801        // }
802
803        $password = Str::password(15);
804        $hashed_password = bcrypt($password);
805
806        $password_expiry = Carbon::now()->addDays(7);
807
808        $data = [
809            "email" => $email,
810            "temp_password_expiry" => $password_expiry->toDateTimeString(),
811            "temp_password" => $hashed_password,
812            "password" => $hashed_password,
813        ];
814
815        if ($user) {
816            $user->password = $hashed_password;
817            $user->temp_password = $hashed_password;
818            $user->temp_password_expiry = $password_expiry->toDateTimeString();
819            $user->save();
820        }
821
822        AdminUserInvitation::updateOrCreate(['email' => $email], $data);
823
824        $this->emailService->send(
825            $email,
826            new AdminCenterAddNewUser(
827                email: $email,
828                password: $password,
829                inviter: $invitation->admin_email,
830                password_expiry: $password_expiry->format("m/d/Y") . " at " . $password_expiry->format("h:i A"),
831                emailSubject: "New Invitation. Welcome to FlyMSG! ðŸ§¡"
832            ),
833            'cac_add_user'
834        );
835
836        return response()->json(
837            data: [
838                'success' => true,
839                'message' => "Temporary password reset sent successfully",
840            ],
841            status: 200
842        );
843    }
844
845    public function create_user_by_csv(Request $request)
846    {
847        $validated_data = $request->validate([
848            "file" => "required",
849        ]);
850
851        $file = $request->file('file');
852
853        $admin = auth()->user();
854        $company_id = $request->company_id;
855
856        // TODO MA
857        // Prcess csv read it into array
858        $users_in_file = [];
859
860        $invitation_sent_count = 0;
861
862        foreach ($users_in_file as $user_object) {
863            $email = strtolower($user_object["email"]);
864            $plan_name = $user_object["plan"];
865
866            $existing_user = false;
867
868            $plan = match ($plan_name) {
869                "Sales Pro" => Plans::whereTitle("FlyMSG.io Sales Pro - YR Plan")->first(),
870                "Starter" => Plans::whereTitle("Starter Yearly")->first(),
871                "Growth" => Plans::whereTitle("Growth Yearly")->first(),
872                "Sales Pro Teams" => Plans::whereTitle("Pro Plan Teams - ENT")->first(),
873                default => null,
874            };
875
876            if (!$plan) {
877                throw new ExpectedException("The selected plan for {$email} was not found.");
878            }
879
880            $user = User::where("email", $email)
881                ->first();
882            if ($user) {
883                $existing_user = true;
884
885                $user->company_id = $company_id;
886                $user->invited_to_company = true;
887                $user->invited_to_company_by_admin = $admin->email;
888                $user->status = "Invited";
889                $user->save();
890
891                $this->emailService->send(
892                    $email,
893                    new AdminCenterAddExistingUser(
894                        admin_email: $admin->email,
895                        email: $user->email,
896                        company: $admin->company->name,
897                    ),
898                    'cac_add_existent_user'
899                );
900            } else {
901                $existing_user = false;
902                $invitation_sent_count++;
903            }
904
905            $invitation = new AdminUserInvitation();
906            $invitation->email = $email;
907            $invitation->plan_id = $plan->id;
908            $invitation->plan = $plan;
909            $invitation->company_id = $company_id;
910            $invitation->admin_email = $user->email;
911            $invitation->save();
912
913            if (!$existing_user) {
914                $this->emailService->send(
915                    $invitation->email,
916                    new InvitationToJoinFlymsgEmail(
917                        email: $invitation->email,
918                        password: ""
919                    ),
920                    'cac_invitation_to_join'
921                );
922            }
923        }
924
925        return response()->json(
926            data: [
927                'success' => true,
928                'message' => "{$invitation_sent_count} users invited successfully",
929            ],
930            status: 200
931        );
932    }
933
934    public function deactivate_user(Request $request, $slug, User $user)
935    {
936        $admin = auth()->user();
937        $company_id = $request->company_id;
938
939        $this->adminUsersService->deactivateUser($user, $admin->id, $company_id);
940
941        return response()->json(data: [
942            'success' => true,
943            'message' => "User deactivated successfully",
944        ], status: 200);
945    }
946
947    public function deactivate_invited_user(Request $request, $slug, $user_id)
948    {
949        $admin = auth()->user();
950        try {
951            $invitation = AdminUserInvitation::find($user_id);
952
953            if (!$invitation) {
954                $user_detail = User::find($user_id);
955
956                $invitation = AdminUserInvitation::where('email', $user_detail->email)->first();
957            }
958
959            if (!empty($user_detail)) {
960                $this->adminUsersService->rejectUserInvitation($user_detail, $admin);
961            }
962
963            $this->adminUsersService->deleteInvitedUser($invitation);
964
965            return response()->json(data: [
966                'success' => true,
967                'message' => "User deactivated successfully",
968            ], status: 200);
969        } catch (\Exception $th) {
970            return response()->json(data: [
971                'success' => false,
972                'message' => "Something went wrong, please try again",
973            ], status: 404);
974        }
975    }
976
977    /**
978     * Hard delete a user fro, the database. This action cannot
979     * be undone.
980     *
981     * @param   Request  $request
982     * @param   User     $user
983     *
984     * @return  JsonResponse
985     */
986    public function delete_user(Request $request, $slug, User $user)
987    {
988        $name = $user->first_name . " " . $user->last_name;
989        $admin = auth()->user();
990
991        $this->adminUsersService->deleteUser($user, $admin);
992
993        return response()->json(data: [
994            'success' => true,
995            'message' => "$name deleted successfully",
996        ], status: 200);
997    }
998
999    public function reset_password(Request $request, $slug, User $user)
1000    {
1001        if ($user->status == "Invited") {
1002            throw new ExpectedException("This user has not signed up yet. Please try again later.");
1003        }
1004
1005        $request = $request->merge(["email" => $user->email]);
1006        $response = $this->broker()->sendResetLink($this->credentials($request));
1007
1008        if ($response != Password::RESET_LINK_SENT) {
1009            throw new ExpectedException("Failed to send password reset link. Please try again later");
1010        }
1011
1012        return response()->json(data: [
1013            'success' => true,
1014            'message' => "Password reset successfully. User will get the link to update their password.",
1015        ], status: 200);
1016    }
1017
1018    public function reset_invitation_password(Request $request, $slug, AdminUserInvitation $invite)
1019    {
1020        if ($invite->status == "Invited") {
1021            throw new ExpectedException("This invite has not signed up yet. Please try again later.");
1022        }
1023
1024        $request = $request->merge(["email" => $invite->email]);
1025        $response = $this->broker()->sendResetLink($this->credentials($request));
1026
1027        if ($response != Password::RESET_LINK_SENT) {
1028            throw new ExpectedException("Failed to send password reset link. Please try again later");
1029        }
1030
1031        return response()->json(data: [
1032            'success' => true,
1033            'message' => "Password reset successfully. User will get the link to update their password.",
1034        ], status: 200);
1035    }
1036
1037    public function resend_user_invitation(Request $request, SendUserInvitationAction $sendUserInvitationAction)
1038    {
1039        $admin = auth()->user();
1040        $validated_data = $request->validate([
1041            'email' => 'required',
1042        ]);
1043
1044        $email = $validated_data['email'];
1045
1046        $invitation = AdminUserInvitation::where('email', $email)->first();
1047
1048        $email = strtolower($email);
1049
1050        if (!$invitation) {
1051            throw new ExpectedException("Previous invitation not found");
1052        }
1053
1054        $user = User::where('email', $email)
1055            ->whereStatus("Invited")
1056            ->first();
1057
1058        $sendInvitationDTO = new SendUserInvitationDTO(
1059            user: $user ?? $invitation,
1060            invitation: $invitation,
1061            newEmail: $email,
1062            adminEmail: $admin->email,
1063            companyName: $admin->company->name,
1064        );
1065
1066        $sendUserInvitationAction->execute($sendInvitationDTO);
1067
1068        return response()->json(data: [
1069            'success' => true,
1070            'message' => "User profile updated successfully",
1071        ], status: 200);
1072    }
1073
1074    public function resend_invitations(Request $request)
1075    {
1076        $admin = auth()->user();
1077        $role = $request->current_role;
1078        $company_id = $request->company_id;
1079        $admin_group_ids = $request->admin_group_ids;
1080
1081        $users = User::select([
1082            "id",
1083            "first_name",
1084            "last_name",
1085            "email",
1086            "role",
1087            "company_id",
1088            "company_group_id",
1089            "sales_pro_team_manager_id",
1090            "status",
1091            "created_at",
1092            "deleted_at",
1093            "deactivated_at",
1094            "avatar"
1095        ])->where("status", "Invited");
1096
1097        $users = $this->filterUsersByAdmin($users, $role, $company_id, $admin_group_ids);
1098        $users = $users->latest()->get();
1099
1100        foreach ($users as $user) {
1101            $userEmail = $user->email;
1102            $invitation = AdminUserInvitation::where('email', $userEmail)->first();
1103            $userEmail = strtolower($user->email);
1104
1105            if (!$invitation) {
1106                continue;
1107            }
1108
1109            if ($user && $user->created_at->diffInMinutes($invitation?->updated_at) > 5) {
1110                $this->emailService->send(
1111                    $userEmail,
1112                    new AdminCenterAddExistingUser(
1113                        admin_email: $admin->email,
1114                        email: $userEmail,
1115                        company: $admin->company->name,
1116                    ),
1117                    'cac_add_existent_user'
1118                );
1119            } else {
1120                $password = Str::random(16);
1121                $encrypted_password = bcrypt($password);
1122                $temp_password_expiry = Carbon::parse($invitation->temp_password_expiry);
1123
1124                $invitation->password = $encrypted_password;
1125                $invitation->temp_password = $encrypted_password;
1126                $invitation->admin_email = $admin->email;
1127                $invitation->email = $userEmail;
1128                $invitation->save();
1129
1130                if ($user) {
1131                    $user->password = $encrypted_password;
1132                    $user->temp_password = $encrypted_password;
1133                    $user->save();
1134                }
1135
1136                $this->emailService->send(
1137                    $userEmail,
1138                    new AdminCenterAddNewUser(
1139                        email: $userEmail,
1140                        password: $password,
1141                        inviter: $admin->email,
1142                        password_expiry: $temp_password_expiry->format("m/d/Y") . " at " . $temp_password_expiry->format("h:i A"),
1143                    ),
1144                    'cac_resend_invitation'
1145                );
1146            }
1147        }
1148
1149        return response()->json(data: [
1150            'success' => true,
1151            'message' => "Invites resent successfully",
1152        ], status: 200);
1153    }
1154
1155    public function move_group(Request $request, $slug, User $user)
1156    {
1157        $validated_data = $request->validate([
1158            'to_group_id' => 'required',
1159        ]);
1160
1161        $group = $this->adminGroupsService->getGroup($validated_data['to_group_id']);
1162
1163        $user = $this->adminUsersService->moveUserToGroup($user, $group);
1164
1165        return response()->json(data: [
1166            'success' => true,
1167            'message' => "User profile updated successfully",
1168            'user' => new AdminCenterUserResource($user->fresh()),
1169        ], status: 200);
1170    }
1171
1172    public function move_group_invite(Request $request, $slug, AdminUserInvitation $invite)
1173    {
1174        $validated_data = $request->validate([
1175            'to_group_id' => 'required',
1176        ]);
1177        $invite->company_group_id = $validated_data['to_group_id'];
1178        $invite->save();
1179
1180        return response()->json(data: [
1181            'success' => true,
1182            'message' => "User invitation updated successfully",
1183            'user' => new AdminCenterUserResource($invite->fresh()),
1184        ], status: 200);
1185    }
1186
1187    public function assign_role(Request $request, $slug, User $user)
1188    {
1189        $validated_data = $request->validate([
1190            'role_name' => 'required',
1191            'groups' => 'sometimes',
1192        ]);
1193
1194        $role = Role::find($validated_data['role_name']);
1195        if (!$role) {
1196            $role = Role::where("name", $validated_data['role_name'])->first();
1197            if (!$role) {
1198                throw new ExpectedException("Role not found");
1199            }
1200        }
1201
1202        $adminRole = Role::where("name", Role::GLOBAL_ADMIN)->first();
1203
1204        if ($role->name != Role::GLOBAL_ADMIN) {
1205            $isAdmin = UserRole::where("role_id", $adminRole->id)
1206                ->where("user_id", $user->id)
1207                ->count() > 0;
1208
1209            if ($isAdmin) {
1210                $roleId = $adminRole->id;
1211                $companyId = $request->company_id;
1212                $currentUserId = $user->id;
1213
1214                $exists = UserRole::raw(function ($collection) use ($roleId, $companyId, $currentUserId) {
1215                    return $collection->aggregate([
1216                        [
1217                            '$lookup' => [
1218                                'from' => 'users',
1219                                'let' => ['userId' => ['$toObjectId' => '$user_id']],
1220                                'pipeline' => [
1221                                    ['$match' => [
1222                                        '$expr' => [
1223                                            '$eq' => ['$$userId', '$_id']
1224                                        ]
1225                                    ]],
1226                                ],
1227                                'as' => 'user'
1228                            ]
1229                        ],
1230                        [
1231                            '$match' => [
1232                                'role_id' => $roleId,
1233                                'user.company_id' => $companyId,
1234                                'user_id' => ['$ne' => $currentUserId]
1235                            ]
1236                        ],
1237                        [
1238                            '$limit' => 1
1239                        ]
1240                    ]);
1241                });
1242
1243                $isLastAdmin = empty($exists->toArray());
1244
1245                if ($isAdmin && $isLastAdmin) {
1246                    throw new ExpectedException("Last admin cannot be demoted", 409);
1247                }
1248            }
1249        }
1250
1251        UserRole::where("user_id", $user->id)->delete();
1252
1253        UserRole::create([
1254            'user_id' => $user->id,
1255            'role_id' => $role->id,
1256        ]);
1257        if ($role->name == Role::GROUP_ADMIN || $role->name = Role::REPORTING_ADMIN) {
1258            $group_ids = $validated_data['groups'] ?? [];
1259
1260            $management_record = $user->sales_pro_team_manager;
1261            if (!$management_record) {
1262                $management_record = new SalesProTeamManager();
1263                $management_record->user_id = $user->id;
1264                $management_record->company_id = $user->company_id;
1265                $management_record->first_name = $user->first_name;
1266                $management_record->last_name = $user->last_name;
1267                $management_record->email = $user->email;
1268                $management_record->save();
1269            }
1270
1271            if (!empty($group_ids)) {
1272                $groups = CompanyGroup::whereIn('_id', $group_ids)->get();
1273                if ($groups->isNotEmpty()) {
1274                    $management_record->groups()->sync($groups);
1275                }
1276            }
1277
1278            $new_group_id = !empty($group_ids) ? $group_ids[0] : null;
1279            if ($user->company_group_id !== $new_group_id) {
1280                $user->company_group_id = $new_group_id;
1281                $user->save();
1282            }
1283        }
1284
1285        return response()->json(data: [
1286            'success' => true,
1287            'message' => "User profile updated successfully",
1288            'user' => new AdminCenterUserResource($user->fresh()),
1289        ], status: 200);
1290    }
1291
1292    public function deactivate_user_bulk(Request $request)
1293    {
1294        $validated_data = $request->validate([
1295            'users' => 'required',
1296        ]);
1297        $admin = auth()->user();
1298        $company_id = $request->company_id;
1299
1300        $this->adminUsersService->deactivateUserBulk($validated_data['users'], $admin->id, $company_id);
1301
1302        return response()->json(data: [
1303            'success' => true,
1304            'message' => "Users deactivated successfully",
1305        ], status: 200);
1306    }
1307
1308    private function _reactive_users(array $userIds)
1309    {
1310        $users = User::withTrashed()->whereIn('_id', $userIds)->get();
1311        $admin = auth()->user();
1312
1313        foreach ($users as $user) {
1314            $user->restore();
1315
1316            $company_id = $user->company_id;
1317            if ($company_id) {
1318                $company = Company::find($user->company_id);
1319                $companyLicense = CompanyLicenses::where('company_id', $company->id)->first();
1320                $community = $companyLicense->business_pro_enterprise_plus ?? [];
1321                $companyName = $company->name;
1322                $companyEmail = $admin->email;
1323                $isPro = in_array('yes_dedicated', $community) || in_array('yes_community', $community);
1324
1325                if ($isPro) {
1326                    ReactivateUserNotification::dispatch($user->email, $companyEmail, $companyName, $this->emailService)->delay(now()->addSeconds(2));
1327                }
1328            }
1329        }
1330    }
1331
1332    private function _assign_plans_to_users(array $usersWithPlan)
1333    {
1334        foreach ($usersWithPlan as $userPlan) {
1335            $userId = $userPlan['user_id'];
1336            $planTitle = match ($userPlan['plan']) {
1337                "Sales Pro" => "FlyMSG.io Sales Pro - YR Plan",
1338                "Growth" => "Growth Yearly",
1339                "Starter" => "Starter Yearly",
1340                "Sales Pro Teams" => "Pro Plan Teams - ENT",
1341                default => $userPlan['plan'],
1342            };
1343
1344            $plan = Plans::where("title", $planTitle)->first();
1345
1346            if ($plan) {
1347                $user = User::withTrashed()->find($userId);
1348                if ($user) {
1349                    $this->_assign_plan($user, $plan, $planTitle, $user->email, true);
1350                }
1351            }
1352        }
1353    }
1354
1355    public function reactivate_user_bulk(Request $request)
1356    {
1357        $validated_data = $request->validate([
1358            'users' => 'required',
1359            'usersWithPlan' => 'sometimes|array',
1360        ]);
1361        $admin = auth()->user();
1362        if (isset($validated_data['users']) && in_array($admin->id, $validated_data['users'])) {
1363            throw new ExpectedException("You cannot reactivate your own account.");
1364        }
1365
1366        $this->_reactive_users($validated_data['users']);
1367
1368        if (!empty($validated_data['usersWithPlan'])) {
1369            $this->_assign_plans_to_users($validated_data['usersWithPlan']);
1370        }
1371
1372        return response()->json(data: [
1373            'success' => true,
1374            'message' => "Users reactivated successfully",
1375        ], status: 200);
1376    }
1377
1378    public function delete_user_bulk(Request $request)
1379    {
1380        $validated_data = $request->validate([
1381            'users' => 'required',
1382        ]);
1383
1384        $admin = auth()->user();
1385        $company_id = $request->company_id;
1386        if (isset($validated_data['users']) && in_array($admin->id, $validated_data['users'])) {
1387            throw new ExpectedException("You cannot delete your own account.");
1388        }
1389
1390        $users = User::whereIn('_id', $validated_data['users'])->get();
1391        foreach ($users as $user) {
1392            // Get the users current plan and cancel it.
1393            $user_sub = $user->subscription("main");
1394            if ($user_sub) {
1395                $plan = $user_sub->plan;
1396                if ($plan->identifier != "freemium") {
1397                    $user_sub->markAsCancelledOnlyInDB();
1398                }
1399                // Deternming the plan and increase the availability in company licenses
1400                $company_license = CompanyLicenses::where('company_id', $company_id)
1401                    ->active()
1402                    ->first();
1403                if ($company_license) {
1404                    $company_license->restoreLicenseCountForDeletedUsers($plan);
1405                }
1406            }
1407            $user->forceDelete();
1408        }
1409
1410        return response()->json(data: [
1411            'success' => true,
1412            'message' => "Users deleted successfully",
1413        ], status: 200);
1414    }
1415
1416    public function reset_password_bulk(Request $request)
1417    {
1418        $validated_data = $request->validate([
1419            'users' => 'required',
1420        ]);
1421        $admin = auth()->user();
1422        $users = $validated_data['users'];
1423        foreach ($users as $email) {
1424            $email = strtolower($email);
1425            $user = User::where('email', $email)->first();
1426            if (!$user) {
1427                // throw new ExpectedException("User not found");
1428                continue;
1429            }
1430
1431            $request = $request->merge(["email" => $email]);
1432            $token = $this->broker()->sendResetLink($this->credentials($request), function ($user, $token) {
1433                return $token;
1434            });
1435
1436            if (in_array($token, [Password::INVALID_USER, Password::RESET_THROTTLED])) {
1437                continue;
1438            }
1439
1440            $this->emailService->send(
1441                $user->email,
1442                new SendResetPasswordRequestedEmail(
1443                    name: $user->first_name . " " . $user->last_name,
1444                    admin_email: $admin->email,
1445                    email: $email,
1446                    token: $token
1447                ),
1448                'cac_send_password_requested'
1449            );
1450        }
1451        return response()->json(data: [
1452            'success' => true,
1453            'message' => "Password reset successfully. User will get the link to update their password.",
1454        ], status: 200);
1455    }
1456
1457    public function resend_user_invitation_bulk(Request $request)
1458    {
1459        $admin = auth()->user();
1460        $validated_data = $request->validate([
1461            'users' => 'required',
1462        ]);
1463        $users = $validated_data['users'];
1464        foreach ($users as $email) {
1465            $user = User::where('email', strtolower($email))->first();
1466
1467            $invitation = AdminUserInvitation::where('email', $email)->first();
1468            $email = strtolower($email);
1469            if (!$invitation) {
1470                // throw new ExpectedException("Previous invitation not found");
1471                continue;
1472            }
1473
1474            if ($user && $user->created_at->diffInMinutes($invitation?->updated_at) > 5) {
1475                $this->emailService->send(
1476                    $email,
1477                    new AdminCenterAddExistingUser(
1478                        admin_email: $admin->email,
1479                        email: $email,
1480                        company: $admin->company->name,
1481                    ),
1482                    'cac_add_existent_user'
1483                );
1484            } else {
1485                $password = Str::random(16);
1486                $encrypted_password = bcrypt($password);
1487                $password_expiry = Carbon::now()->addDays(7);
1488
1489                $invitation->password = $encrypted_password;
1490                $invitation->temp_password = $encrypted_password;
1491                $invitation->temp_password_expiry = $password_expiry->toDateTimeString();
1492                $invitation->admin_email = $request->user()->email;
1493                $invitation->email = $email;
1494                $invitation->save();
1495
1496                $this->emailService->send(
1497                    $email,
1498                    new InvitationToJoinFlymsgEmail(
1499                        email: $email,
1500                        password: $password
1501                    ),
1502                    'cac_invitation_to_join'
1503                );
1504            }
1505        }
1506
1507        return response()->json(data: [
1508            'success' => true,
1509            'message' => "User profile updated successfully",
1510        ], status: 200);
1511    }
1512
1513    public function move_group_bulk(Request $request)
1514    {
1515        $validated_data = $request->validate([
1516            'users' => 'required',
1517            'to_group_id' => 'required',
1518        ]);
1519
1520        $group = $this->adminGroupsService->getGroup($validated_data['to_group_id']);
1521
1522        $users = $this->adminUsersService->moveUsersToGroup($validated_data['users'], $group);
1523
1524        return response()->json(data: [
1525            'success' => true,
1526            'message' => "User profile updated successfully",
1527            'users' => AdminCenterUserResource::collection($users),
1528        ], status: 200);
1529    }
1530
1531    /**
1532     * Checks if a group/subgroup is unique in a company
1533     *
1534     * @param   Request  $request {name:string}
1535     *
1536     * @return  JsonResponse
1537     */
1538    public function group_exists(Request $request)
1539    {
1540        $validated_data = $request->validate([
1541            'name' => 'required|string'
1542        ]);
1543        $name = $validated_data["name"];
1544        $company_id = $request->company_id;
1545
1546        $exists = CompanyGroup::where([
1547            ["name", $name],
1548            ["company_id", $company_id]
1549        ])->exists();
1550
1551        return response()->json([
1552            'success' => true,
1553            'exists' => $exists ? true : false,
1554            'message' => $exists ? "The name: $name has already been taken." : "The name $name is available.",
1555        ], 200);
1556    }
1557
1558    /**
1559     * Creates a new group. You can assign members of the
1560     * group too if you like.
1561     *
1562     * @param   Request  $request {name:string, users:[array if user IDs]}
1563     *
1564     * @return  JsonResponse
1565     */
1566    public function create_group(Request $request)
1567    {
1568        $company_id = $request->company_id;
1569        $validated_data = $request->validate([
1570            'name' => 'required',
1571            'users' => 'sometimes',
1572        ]);
1573
1574        $group = $this->adminGroupsService->createGroup($validated_data["name"], $company_id);
1575
1576        $this->adminUsersService->moveUsersToGroup($validated_data['users'] ?? [], $group);
1577
1578        return response()->json(data: [
1579            'success' => true,
1580            'message' => "New group $group->name added",
1581            'group' => new AdminCenterCompanyGroupResource($group->load('users')),
1582        ], status: 200);
1583    }
1584
1585    public function update_group(Request $request, $slug, CompanyGroup $group)
1586    {
1587        $validated_data = $request->validate([
1588            'name' => 'required',
1589        ]);
1590
1591        $result = $this->adminGroupsService->updateGroup($group, $validated_data["name"], $request->company_id);
1592
1593        return response()->json(data: $result, status: 200);
1594    }
1595
1596    public function delete_group(Request $request, $slug, CompanyGroup $group)
1597    {
1598        // get group instancy id
1599        $groupInstancyId = isset($group->instancy_id) ? $group->instancy_id : '';
1600
1601        if ($group->users()->count() > 0) {
1602            $group->users()->update(['company_group_id' => null]);
1603            $user_ids = $group->users()->pluck('_id')->toArray();
1604            $this->adminUsersService->moveUsersToGroup($user_ids, null);
1605        }
1606
1607        // Of a top parent group is being deleted, delete subgroups too?
1608        if ($group->subgroups()->count() > 0) {
1609            foreach ($group->subgroups as $subgroup) {
1610                $subgroup->users()->update(['company_group_id' => null]);
1611
1612                $user_ids = $subgroup->users()->pluck('_id')->toArray();
1613                $this->adminUsersService->moveUsersToGroup($user_ids, null);
1614
1615                $subgroup->delete();
1616            }
1617        }
1618        $group->delete();
1619
1620        // after above delete the group on instancy
1621        if ($groupInstancyId) {
1622            $job = DeleteInstancyGroup::dispatch($groupInstancyId);
1623            if ($job) {
1624                $job->delay(now()->addMinutes(5));
1625            }
1626        }
1627
1628        return response()->json(data: [
1629            'success' => true,
1630            'message' => "Group deleted successfully",
1631        ], status: 200);
1632    }
1633
1634    public function add_users_to_group(Request $request, $slug, CompanyGroup $group)
1635    {
1636        $validated_data = $request->validate([
1637            'users' => 'required',
1638        ]);
1639
1640        $this->adminUsersService->moveUsersToGroup($validated_data['users'], $group);
1641
1642        return response()->json(data: [
1643            'success' => true,
1644            'message' => "Updated group users successfully",
1645        ], status: 200);
1646    }
1647
1648    public function add_subgroup_to_group(Request $request, $slug, CompanyGroup $group)
1649    {
1650        $company_id = $request->company_id;
1651
1652        $validated_data = $request->validate([
1653            'name' => 'required',
1654            'users' => 'sometimes',
1655        ]);
1656
1657        $subgroup = $this->adminGroupsService->createGroup($validated_data["name"], $company_id, $group);
1658
1659        $this->adminUsersService->moveUsersToGroup($validated_data['users'] ?? [], $subgroup);
1660
1661        return response()->json(data: [
1662            'success' => true,
1663            'message' => "New subgroup added",
1664            'group' => $subgroup->load('users'),
1665        ], status: 200);
1666    }
1667
1668    public function export_csv(Request $request)
1669    {
1670        $users = $request->users ? explode(',', $request->users) : [];
1671        $only_deactivated_users = $request->deactivated == "true" ? true : false;
1672        return (new UsersExport($only_deactivated_users, $users))->download('users.csv');
1673    }
1674
1675    public function import_csv(Request $request)
1676    {
1677        $request->validate([
1678            'csv_file' => 'required',
1679        ]);
1680
1681        $file = $request->file('csv_file');
1682
1683        (new UsersImport)->import($file);
1684
1685        return response()->json([
1686            'success' => true,
1687            'message' => 'CSV imported successfully and file deleted.',
1688        ], 200);
1689    }
1690
1691    public function reporting_licenses(Request $request)
1692    {
1693        $filters = new FindUsersOverviewFilter(
1694            fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null,
1695            toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null,
1696            userIds: array_filter(explode(",", $request->user_ids), function ($value) {
1697                return $value !== "";
1698            }),
1699            groupIds: array_filter(explode(",", $request->group_ids), function ($value) {
1700                return $value !== "";
1701            }),
1702            subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) {
1703                return $value !== "";
1704            }),
1705            companyIds: $request->company_ids ? explode(",", $request->company_ids) : null,
1706            currentRole: $request->current_role,
1707            companyId: $request->company_id,
1708            adminGroupIds: $request->admin_group_ids,
1709            monthPeriod: 12,
1710        );
1711
1712        $data = $this->accountCenterReportingService->findLicenseOverview($filters);
1713
1714        return response()->json(data: [
1715            'success' => true,
1716            'licenses' => $data,
1717        ], status: 200);
1718    }
1719
1720    public function reporting_roi_spotlight(Request $request, RoiSpotlightAction $roiSpotlightAction)
1721    {
1722        $filters = new ReportingRequestDTO(
1723            fromDate: $request->fromDate,
1724            toDate: $request->toDate,
1725            companyId: $request->company_id,
1726            adminGroupIds: $request->admin_group_ids,
1727            userIds: $request->user_ids ? $request->user_ids : null,
1728            groupIds: $request->group_ids ? $request->group_ids : null,
1729            subgroupIds: $request->subgroup_ids ? $request->subgroup_ids : null,
1730            role: $request->current_role,
1731        );
1732
1733        $data = $roiSpotlightAction->execute($filters);
1734
1735        return response()->json(data: [
1736            'success' => true,
1737            'data' => $data,
1738        ], status: 200);
1739    }
1740
1741    public function reporting_productivity_spotlight(Request $request, ProductivitySpotlightAction $productivitySpotlightAction)
1742    {
1743        $filters = new ReportingRequestDTO(
1744            fromDate: $request->fromDate,
1745            toDate: $request->toDate,
1746            companyId: $request->company_id,
1747            adminGroupIds: $request->admin_group_ids,
1748            userIds: $request->user_ids ? $request->user_ids : null,
1749            groupIds: $request->group_ids ? $request->group_ids : null,
1750            subgroupIds: $request->subgroup_ids ? $request->subgroup_ids : null,
1751            role: $request->current_role,
1752        );
1753
1754        $data = $productivitySpotlightAction->execute($filters);
1755
1756        return response()->json(data: [
1757            'success' => true,
1758            'data' => $data,
1759        ], status: 200);
1760    }
1761
1762    public function reporting_total_characters_typed_spotlight(Request $request, TotalCharactersTypedSpotlightAction $totalCharactersTypedSpotlightAction)
1763    {
1764        $filters = new ReportingRequestDTO(
1765            fromDate: $request->fromDate,
1766            toDate: $request->toDate,
1767            companyId: $request->company_id,
1768            adminGroupIds: $request->admin_group_ids,
1769            userIds: $request->user_ids ? $request->user_ids : null,
1770            groupIds: $request->group_ids ? $request->group_ids : null,
1771            subgroupIds: $request->subgroup_ids ? $request->subgroup_ids : null,
1772            role: $request->current_role,
1773        );
1774
1775        $data = $totalCharactersTypedSpotlightAction->execute($filters);
1776
1777        return response()->json(data: [
1778            'success' => true,
1779            'data' => $data,
1780        ], status: 200);
1781    }
1782
1783    public function reporting_total_fly_grammar_spotlight(Request $request, TotalFlyGrammarSpotlightAction $totalFlyGrammarSpotlightAction)
1784    {
1785        $filters = new ReportingRequestDTO(
1786            fromDate: $request->fromDate,
1787            toDate: $request->toDate,
1788            companyId: $request->company_id,
1789            adminGroupIds: $request->admin_group_ids,
1790            userIds: $request->user_ids ? $request->user_ids : null,
1791            groupIds: $request->group_ids ? $request->group_ids : null,
1792            subgroupIds: $request->subgroup_ids ? $request->subgroup_ids : null,
1793            role: $request->current_role,
1794        );
1795
1796        $data = $totalFlyGrammarSpotlightAction->execute($filters);
1797
1798        return response()->json(data: [
1799            'success' => true,
1800            'data' => $data,
1801        ], status: 200);
1802    }
1803
1804    public function reporting_total_fly_cuts_spotlight(Request $request, TotalFlyCutsSpotlightAction $totalFlyCutsSpotlightAction)
1805    {
1806        $filters = new ReportingRequestDTO(
1807            fromDate: $request->fromDate,
1808            toDate: $request->toDate,
1809            companyId: $request->company_id,
1810            adminGroupIds: $request->admin_group_ids,
1811            userIds: $request->user_ids ? $request->user_ids : null,
1812            groupIds: $request->group_ids ? $request->group_ids : null,
1813            subgroupIds: $request->subgroup_ids ? $request->subgroup_ids : null,
1814            role: $request->current_role,
1815        );
1816
1817        $data = $totalFlyCutsSpotlightAction->execute($filters);
1818
1819        return response()->json(data: [
1820            'success' => true,
1821            'data' => $data,
1822        ], status: 200);
1823    }
1824
1825    public function reporting_flymsg_coach_level(Request $request, FmsCoachLevelSpotlightAction $fmsCoachLevelSpotlightAction)
1826    {
1827        $filters = new ReportingRequestDTO(
1828            fromDate: $request->fromDate,
1829            toDate: $request->toDate,
1830            companyId: $request->company_id,
1831            adminGroupIds: $request->admin_group_ids,
1832            userIds: $request->user_ids ? $request->user_ids : null,
1833            groupIds: $request->group_ids ? $request->group_ids : null,
1834            subgroupIds: $request->subgroup_ids ? $request->subgroup_ids : null,
1835            role: $request->current_role,
1836        );
1837
1838        $data = $fmsCoachLevelSpotlightAction->execute($filters);
1839
1840        return response()->json([
1841            'success' => true,
1842            'data' => $data,
1843        ], 200);
1844    }
1845
1846    public function reporting_flycuts_created(Request $request)
1847    {
1848        $filters = new FindUsersOverviewFilter(
1849            fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null,
1850            toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null,
1851            userIds: array_filter(explode(",", $request->user_ids), function ($value) {
1852                return $value !== "";
1853            }),
1854            groupIds: array_filter(explode(",", $request->group_ids), function ($value) {
1855                return $value !== "";
1856            }),
1857            subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) {
1858                return $value !== "";
1859            }),
1860            companyIds: $request->company_ids ? explode(",", $request->company_ids) : null,
1861            currentRole: $request->current_role,
1862            companyId: $request->company_id,
1863            adminGroupIds: $request->admin_group_ids,
1864            monthPeriod: 12,
1865            userDefined: true,
1866        );
1867
1868        $shortcuts = $this->accountCenterReportingService->findShortcut($filters);
1869
1870        $data = [
1871            "chart" => $shortcuts['chart'],
1872            "total_flycuts_created" => number_format($shortcuts['total_shortcut_created'], 0, ".", ","),
1873            "average_flycuts_per_active_user" => number_format(round($shortcuts['average_shortcut_per_active_user'], 2), 2, ".", ","),
1874        ];
1875
1876        return response()->json(data: [
1877            'success' => true,
1878            'data' => $data,
1879        ], status: 200);
1880    }
1881
1882    public function reporting_flycuts_created_top_users(Request $request)
1883    {
1884        return response()->json(data: [
1885            'success' => true,
1886            'users' => $this->getTop5($request, 'flycuts_created'),
1887        ]);
1888    }
1889
1890    public function reporting_flyplates_added(Request $request)
1891    {
1892
1893        $filters = new FindUsersOverviewFilter(
1894            fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null,
1895            toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null,
1896            userIds: array_filter(explode(",", $request->user_ids), function ($value) {
1897                return $value !== "";
1898            }),
1899            groupIds: array_filter(explode(",", $request->group_ids), function ($value) {
1900                return $value !== "";
1901            }),
1902            subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) {
1903                return $value !== "";
1904            }),
1905            companyIds: $request->company_ids ? explode(",", $request->company_ids) : null,
1906            currentRole: $request->current_role,
1907            companyId: $request->company_id,
1908            adminGroupIds: $request->admin_group_ids,
1909            monthPeriod: 12,
1910            userDefined: false,
1911        );
1912
1913        $shortcuts = $this->accountCenterReportingService->findShortcut($filters);
1914
1915        $data = [
1916            "chart" => $shortcuts['chart'],
1917            "total_flyplate_created" => number_format($shortcuts['total_shortcut_created'], 0, ".", ","),
1918            "average_flyplate_per_active_user" => number_format(round($shortcuts['average_shortcut_per_active_user'], 2), 2, ".", ","),
1919        ];
1920
1921        return response()->json(data: [
1922            'success' => true,
1923            'data' => $data,
1924        ], status: 200);
1925    }
1926
1927    public function reporting_flyplates_added_top_users(Request $request)
1928    {
1929        return response()->json(data: [
1930            'success' => true,
1931            'users' => $this->getTop5($request, 'flyplates_added'),
1932        ]);
1933    }
1934
1935    public function reporting_sentence_rewrite_ai(Request $request)
1936    {
1937
1938        $filters = new FindUsersOverviewFilter(
1939            fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null,
1940            toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null,
1941            userIds: array_filter(explode(",", $request->user_ids), function ($value) {
1942                return $value !== "";
1943            }),
1944            groupIds: array_filter(explode(",", $request->group_ids), function ($value) {
1945                return $value !== "";
1946            }),
1947            subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) {
1948                return $value !== "";
1949            }),
1950            companyIds: $request->company_ids ? explode(",", $request->company_ids) : null,
1951            currentRole: $request->current_role,
1952            companyId: $request->company_id,
1953            adminGroupIds: $request->admin_group_ids,
1954            monthPeriod: 12,
1955            userDefined: false,
1956            feature: "sentence_rewrite",
1957        );
1958
1959        $flyMsgAI = $this->accountCenterReportingService->findFlyMsgAI($filters);
1960
1961        $data = [
1962            "chart" => $flyMsgAI['chart'],
1963            "total_sentence_rewrite_ai_created" => number_format($flyMsgAI['total_flymsg_ai'], 0, ".", ","),
1964            "average_sentence_rewrite_ai_per_active_user" => number_format(round($flyMsgAI['average_flymsgai_per_active_user'], 2), 2, ".", ","),
1965        ];
1966
1967        return response()->json(data: [
1968            'success' => true,
1969            'data' => $data,
1970        ], status: 200);
1971    }
1972
1973    public function reporting_sentence_rewrite_ai_used_top_users(Request $request)
1974    {
1975        return response()->json(data: [
1976            'success' => true,
1977            'users' => $this->getTop5($request, 'sentence_rewrite_count'),
1978        ]);
1979    }
1980
1981    public function reporting_paragraph_rewrite_ai(Request $request)
1982    {
1983
1984        $filters = new FindUsersOverviewFilter(
1985            fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null,
1986            toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null,
1987            userIds: array_filter(explode(",", $request->user_ids), function ($value) {
1988                return $value !== "";
1989            }),
1990            groupIds: array_filter(explode(",", $request->group_ids), function ($value) {
1991                return $value !== "";
1992            }),
1993            subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) {
1994                return $value !== "";
1995            }),
1996            companyIds: $request->company_ids ? explode(",", $request->company_ids) : null,
1997            currentRole: $request->current_role,
1998            companyId: $request->company_id,
1999            adminGroupIds: $request->admin_group_ids,
2000            monthPeriod: 12,
2001            userDefined: false,
2002            feature: "paragraph_rewrite",
2003        );
2004
2005        $flyMsgAI = $this->accountCenterReportingService->findFlyMsgAI($filters);
2006
2007        $data = [
2008            "chart" => $flyMsgAI['chart'],
2009            "total_paragraph_rewrite_ai_created" => number_format($flyMsgAI['total_flymsg_ai'], 0, ".", ","),
2010            "average_paragraph_rewrite_ai_per_active_user" => number_format(round($flyMsgAI['average_flymsgai_per_active_user'], 2), 2, ".", ","),
2011        ];
2012
2013        return response()->json(data: [
2014            'success' => true,
2015            'data' => $data,
2016        ], status: 200);
2017    }
2018
2019    public function reporting_paragraph_rewrite_ai_used_top_users(Request $request)
2020    {
2021        return response()->json(data: [
2022            'success' => true,
2023            'users' => $this->getTop5($request, 'paragraph_rewrite_count'),
2024        ]);
2025    }
2026
2027    public function reporting_flyengage_ai(Request $request)
2028    {
2029
2030        $filters = new FindUsersOverviewFilter(
2031            fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null,
2032            toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null,
2033            userIds: array_filter(explode(",", $request->user_ids), function ($value) {
2034                return $value !== "";
2035            }),
2036            groupIds: array_filter(explode(",", $request->group_ids), function ($value) {
2037                return $value !== "";
2038            }),
2039            subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) {
2040                return $value !== "";
2041            }),
2042            companyIds: $request->company_ids ? explode(",", $request->company_ids) : null,
2043            currentRole: $request->current_role,
2044            companyId: $request->company_id,
2045            adminGroupIds: $request->admin_group_ids,
2046            monthPeriod: 12,
2047            userDefined: false,
2048            feature: "flyengage",
2049        );
2050
2051        $flyMsgAI = $this->accountCenterReportingService->findFlyMsgAI($filters);
2052
2053        $data = [
2054            "chart" => $flyMsgAI['chart'],
2055            "total_flyengage_ai_created" => number_format($flyMsgAI['total_flymsg_ai'], 0, ".", ","),
2056            "average_flyengage_ai_per_active_user" => number_format(round($flyMsgAI['average_flymsgai_per_active_user'], 2), 2, ".", ","),
2057        ];
2058
2059        return response()->json(data: [
2060            'success' => true,
2061            'data' => $data,
2062        ], status: 200);
2063    }
2064
2065    public function reporting_flyengage_ai_used_top_users(Request $request)
2066    {
2067        return response()->json(data: [
2068            'success' => true,
2069            'users' => $this->getTop5($request, 'flyengage_count'),
2070        ]);
2071    }
2072
2073    public function reporting_flypost_ai(Request $request)
2074    {
2075        $filters = new FindUsersOverviewFilter(
2076            fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null,
2077            toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null,
2078            userIds: array_filter(explode(",", $request->user_ids), function ($value) {
2079                return $value !== "";
2080            }),
2081            groupIds: array_filter(explode(",", $request->group_ids), function ($value) {
2082                return $value !== "";
2083            }),
2084            subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) {
2085                return $value !== "";
2086            }),
2087            companyIds: $request->company_ids ? explode(",", $request->company_ids) : null,
2088            currentRole: $request->current_role,
2089            companyId: $request->company_id,
2090            adminGroupIds: $request->admin_group_ids,
2091            monthPeriod: 12,
2092            userDefined: false,
2093            feature: "flypost",
2094        );
2095
2096        $flyMsgAI = $this->accountCenterReportingService->findFlyMsgAI($filters);
2097
2098        $data = [
2099            "chart" => $flyMsgAI['chart'],
2100            "total_flypost_ai_created" => number_format($flyMsgAI['total_flymsg_ai'], 0, ".", ","),
2101            "average_flypost_ai_per_active_user" => number_format(round($flyMsgAI['average_flymsgai_per_active_user'], 2), 2, ".", ","),
2102        ];
2103
2104        return response()->json(data: [
2105            'success' => true,
2106            'data' => $data,
2107        ], status: 200);
2108    }
2109
2110    public function reporting_flypost_ai_used_top_users(Request $request)
2111    {
2112        return response()->json(data: [
2113            'success' => true,
2114            'users' => $this->getTop5($request, 'flypost_count'),
2115        ]);
2116    }
2117
2118    private function getTop5(Request $request, string $property)
2119    {
2120        $filter = new ReportingRequestDTO(
2121            fromDate: !empty($request->fromDate) ? Carbon::parse($request->fromDate)->startOfDay() : null,
2122            toDate: !empty($request->toDate) ? Carbon::parse($request->toDate)->endOfDay() : null,
2123            companyId: $request->company_id,
2124            adminGroupIds: $request->admin_group_ids,
2125            userIds: $request->user_ids,
2126            groupIds: $request->group_ids,
2127            subgroupIds: $request->subgroup_ids,
2128            role: $request->current_role,
2129            companyIds: $request->company_ids ? explode(",", $request->company_ids) : null,
2130        );
2131
2132        $top5 = $this->accountCenterReportingService->getTop5Users($filter, $property);
2133
2134        // Get the top 5 users
2135        $top_5_users = $top5->map(function ($top) use ($property) {
2136            $user = User::firstWhere('_id', $top['user_id']);
2137
2138            if ($user) {
2139                $full_name = $user->first_name . ' ' . $user->last_name;
2140
2141                return ['name' => $full_name, 'count' => number_format($top[$property], 0, ".", ","), 'image' => $user->avatar];
2142            }
2143        });
2144
2145        return $top_5_users;
2146    }
2147
2148    public function reporting_characters_typed_saving_top_users(Request $request)
2149    {
2150        return response()->json(data: [
2151            'success' => true,
2152            'users' => $this->getTop5($request, 'characters_typed'),
2153        ]);
2154    }
2155
2156    public function reporting_fly_grammar_top_users(Request $request)
2157    {
2158        return response()->json(data: [
2159            'success' => true,
2160            'users' => $this->getTop5($request, 'fly_grammar_actions'),
2161        ]);
2162    }
2163
2164    public function reporting_fly_cuts_top_users(Request $request)
2165    {
2166        return response()->json(data: [
2167            'success' => true,
2168            'users' => $this->getTop5($request, 'flycut_count'),
2169        ]);
2170    }
2171
2172    public function reporting_fly_grammar_accepted_top_users(Request $request)
2173    {
2174        return response()->json(data: [
2175            'success' => true,
2176            'users' => $this->getTop5($request, 'fly_grammar_accepted'),
2177        ]);
2178    }
2179
2180    public function reporting_fly_grammar_autocorrect_top_users(Request $request)
2181    {
2182        return response()->json(data: [
2183            'success' => true,
2184            'users' => $this->getTop5($request, 'fly_grammar_autocorrect'),
2185        ]);
2186    }
2187
2188    public function reporting_fly_grammar_autocomplete_top_users(Request $request)
2189    {
2190        return response()->json(data: [
2191            'success' => true,
2192            'users' => $this->getTop5($request, 'fly_grammar_autocomplete'),
2193        ]);
2194    }
2195
2196    public function reporting_time_saving_top_users(Request $request)
2197    {
2198        return response()->json(data: [
2199            'success' => true,
2200            'users' => $this->getTop5($request, 'time_saved'),
2201        ]);
2202    }
2203
2204    public function reporting_cost_saving_top_users(Request $request)
2205    {
2206        return response()->json(data: [
2207            'success' => true,
2208            'users' => $this->getTop5($request, 'cost_savings'),
2209        ]);
2210    }
2211
2212    public function reporting_active_users(Request $request)
2213    {
2214        $filters = new FindUsersOverviewFilter(
2215            fromDate: $request->fromDate ? Carbon::parse($request->fromDate)->startOfDay() : null,
2216            toDate: $request->toDate ? Carbon::parse($request->toDate)->endOfDay() : null,
2217            userIds: array_filter(explode(",", $request->user_ids), function ($value) {
2218                return $value !== "";
2219            }),
2220            groupIds: array_filter(explode(",", $request->group_ids), function ($value) {
2221                return $value !== "";
2222            }),
2223            subgroupIds: array_filter(explode(",", $request->subgroup_ids), function ($value) {
2224                return $value !== "";
2225            }),
2226            companyIds: $request->company_ids ? explode(",", $request->company_ids) : null,
2227            currentRole: $request->current_role,
2228            companyId: $request->company_id,
2229            adminGroupIds: $request->admin_group_ids,
2230            monthPeriod: 12,
2231        );
2232
2233        $data = $this->accountCenterReportingService->findUsersOverview($filters);
2234
2235        return response()->json(data: [
2236            'success' => true,
2237            'data' => $data,
2238        ], status: 200);
2239    }
2240
2241    public function reporting_extension_usage(Request $request)
2242    {
2243        $admin = auth()->user();
2244        $roles = $admin->role;
2245        $role = role($roles);
2246        $company_id = $request->company_id;
2247        $admin_group_ids = $request->admin_group_ids;
2248
2249        $users = User::select([
2250            "id",
2251            "first_name",
2252            "last_name",
2253            "company_group_id",
2254            "company_id",
2255            "deleted_at",
2256            "avatar"
2257        ]);
2258
2259        $start_date = $request->fromDate;
2260        $end_date = $request->toDate;
2261
2262        if ($start_date && $end_date) {
2263            $start_date = Carbon::parse($start_date)->startOfDay();
2264            $end_date = Carbon::parse($end_date)->endOfDay();
2265        }
2266
2267        $user_ids = explode(",", $request->user_ids);
2268        $user_ids = array_filter($user_ids, function ($value) {
2269            return $value !== "";
2270        });
2271        if (count($user_ids) > 0) {
2272            $users = $users->whereIn("_id", $user_ids);
2273        }
2274
2275        $hasNotAssignedGroup = in_array("-1", explode(",", $request->group_ids));
2276
2277        if ($hasNotAssignedGroup) {
2278            $users = $users->whereNull("company_group_id");
2279        }
2280
2281        $group_ids = explode(",", $request->group_ids);
2282        $group_ids = array_filter($group_ids, function ($value) {
2283            return $value !== "" && $value !== "-1";
2284        });
2285
2286        if (count($group_ids) > 0) {
2287            $users = $users->whereIn("company_group_id", $group_ids);
2288        }
2289
2290        $subgroup_ids = explode(",", $request->subgroup_ids);
2291        $subgroup_ids = array_filter($subgroup_ids, function ($value) {
2292            return $value !== "";
2293        });
2294        if (count($subgroup_ids) > 0) {
2295            $users = $users->whereIn("company_group_id", $subgroup_ids);
2296        }
2297
2298        $users = $this->filterUsersByGroupIds($users, $role, $group_ids, $company_id, $admin_group_ids);
2299
2300        $users = $users->whereStatus("Active");
2301
2302        $users = $users->get();
2303        $ids = $users->pluck("id")->toArray();
2304
2305        $extensions_data = HubspotProperties::whereIn("flymsg_id", $ids);
2306
2307        if ($start_date && $end_date) {
2308            $extensions_data = $extensions_data->whereBetween("created_at", [
2309                new UTCDateTime($start_date->getTimestamp() * 1000),
2310                new UTCDateTime($end_date->getTimestamp() * 1000),
2311            ]);
2312        }
2313
2314        $extensions_data = $extensions_data->orderBy('created_at', 'desc')
2315            ->get()
2316            ->unique('flymsg_id');
2317
2318        $firstDate = $start_date;
2319        $lastDate = $end_date;
2320
2321        if (!$firstDate) {
2322            $firstDate = $extensions_data->min("created_at");
2323        }
2324
2325        if (!$lastDate) {
2326            $lastDate = $extensions_data->max("created_at");
2327        }
2328
2329        $months = $lastDate->diffInMonths($firstDate);
2330        $chart = $this->_make_line_chart_data_extension($extensions_data, $months, $firstDate);
2331
2332        $data = [
2333            "chart" => $chart,
2334        ];
2335
2336        return response()->json([
2337            'success' => true,
2338            'data' => $data,
2339        ], 200);
2340    }
2341
2342    public function reporting_user_details(Request $request)
2343    {
2344        $admin = auth()->user();
2345        $roles = $admin->role;
2346        $role = role($roles);
2347        $company_id = $request->company_id;
2348        $admin_group_ids = $request->admin_group_ids;
2349
2350        $start_date = $request->fromDate;
2351        $end_date = $request->toDate;
2352
2353        $users = User::withTrashed()
2354            ->select([
2355                "id",
2356                "first_name",
2357                "last_name",
2358                "company_group_id",
2359                "company_id",
2360                "deleted_at",
2361            ]);
2362
2363        if ($start_date && $end_date) {
2364            $start_date = Carbon::parse($start_date);
2365            $end_date = Carbon::parse($end_date);
2366
2367            $start_date = Carbon::now()->subMonths(12)->startOfMonth();
2368            $end_date = Carbon::now()->endOfMonth();
2369
2370            $users = $users->whereBetween("created_at", [
2371                new UTCDateTime($start_date->getTimestamp() * 1000),
2372                new UTCDateTime($end_date->getTimestamp() * 1000),
2373            ]);
2374        }
2375
2376        $users = $this->filterUsersByAdmin($users, $role, $company_id, $admin_group_ids);
2377
2378        $users = $users->get();
2379        $ids = $users->pluck("id")->toArray();
2380
2381        // TODO MA filter this data by the dates too?
2382        // - Total # of Characters Typed by FlyMSG by User
2383        // - Total Time Saved by FlyMSG by User
2384        // - Total Cost Savings by FlyMSG by User
2385
2386        $properties = HubspotProperties::whereIn("flymsg_id", $ids);
2387
2388        if ($start_date && $end_date) {
2389            $properties = $properties->whereBetween("created_at", [
2390                new UTCDateTime($start_date->getTimestamp() * 1000),
2391                new UTCDateTime($end_date->getTimestamp() * 1000),
2392            ]);
2393        }
2394
2395        $properties = $properties->get();
2396
2397        $properties = UserDetailsReportResource::collection($properties);
2398
2399        return response()->json([
2400            'success' => true,
2401            'users' => $properties,
2402        ], 200);
2403    }
2404
2405    public function reporting_get_columns(Request $request)
2406    {
2407        $admin = auth()->user();
2408        $company_id = $request->company_id;
2409
2410        $default_columns = collect();
2411
2412        $default_columns = $default_columns->push([
2413            "key" => "first_name",
2414            "value" => "First Name",
2415            "checked" => true,
2416        ]);
2417        $default_columns = $default_columns->push([
2418            "key" => "last_name",
2419            "value" => "Last Name",
2420            "checked" => true,
2421        ]);
2422        $default_columns = $default_columns->push([
2423            "key" => "email",
2424            "value" => "Email",
2425            "checked" => true,
2426        ]);
2427
2428        $columns = UserDetailsColumnSetting::where("user_id", $admin->id)
2429            ->where("company_id", $company_id)
2430            ->get();
2431
2432        if (count($columns) == 0) {
2433            $columns = collect(Constants::ADMIN_CENTER_USERS_TABLE_REPORTING_TABLE_HEADERS);
2434        } else {
2435            $columns = UserDetailsReportingResource::collection($columns);
2436            $columns = array_merge($default_columns->toArray(), $columns->toArray($request));
2437        }
2438
2439        return response()->json([
2440            'success' => true,
2441            'columns' => $columns,
2442        ], 200);
2443    }
2444
2445    public function reporting_save_columns(Request $request)
2446    {
2447        $validated_data = $request->validate([
2448            "columns" => "required",
2449        ]);
2450
2451        $admin = auth()->user();
2452        $roles = $admin->role;
2453        $role = role($roles);
2454        $company_id = $request->company_id;
2455        $admin_group_ids = $request->admin_group_ids;
2456
2457        $columns = $validated_data["columns"];
2458
2459        foreach ($columns as $column) {
2460            $users_column = UserDetailsColumnSetting::where("user_id", $admin->id)
2461                ->where("key", $column["key"])
2462                ->first();
2463
2464            if ($users_column) {
2465                if ($users_column->column == "first_name" || $users_column->column == "last_name" || $users_column->column == "email") {
2466                    continue;
2467                }
2468            }
2469
2470            $data = [
2471                "company_id" => $company_id,
2472                "user_id" => $admin->id,
2473                "key" => $column["key"],
2474                "value" => $column["value"],
2475                "checked" => $column["checked"],
2476            ];
2477
2478            if ($users_column) {
2479                $users_column->update($data);
2480            } else {
2481                UserDetailsColumnSetting::create($data);
2482            }
2483        }
2484
2485        $users = User::select([
2486            "id",
2487            "first_name",
2488            "last_name",
2489            "company_group_id",
2490            "company_id",
2491            "deleted_at",
2492            "avatar"
2493        ]);
2494
2495        $users = $this->filterUsersByAdmin($users, $role, $company_id, $admin_group_ids);
2496
2497        $ids = $users->pluck("id")->toArray();
2498
2499        $columns = UserDetailsColumnSetting::whereIn("user_id", $ids)
2500            ->where("company_id", $company_id)
2501            ->get();
2502
2503        return response()->json([
2504            'success' => true,
2505            'column' => $columns,
2506        ], 200);
2507    }
2508
2509    public function export_user_details_csv(Request $request)
2510    {
2511        $validated_data = $request->validate([
2512            "columns" => "required",
2513        ]);
2514
2515        $admin = auth()->user();
2516        $company_id = $request->company_id;
2517
2518        $columns = UserDetailsColumnSetting::whereIn("user_id", $admin->id)
2519            ->where("company_id", $company_id)
2520            ->get();
2521
2522        if (count($columns) == 0) {
2523            $columns = collect(Constants::ADMIN_CENTER_USERS_TABLE_REPORTING_TABLE_HEADERS);
2524        }
2525
2526        return response()->json([
2527            'success' => true,
2528            'columns' => $columns,
2529        ], 200);
2530    }
2531
2532    public function reset_invited_user_password(Request $request)
2533    {
2534        $validated_data = $request->validate([
2535            "password" => "required|confirmed|min:8|max:25",
2536        ]);
2537
2538        $user = $request->user();
2539
2540        $user->password = Hash::make($validated_data['password']);
2541
2542        if ($request->first_name) {
2543            $user->first_name = $request->first_name;
2544        }
2545
2546        if ($request->last_name) {
2547            $user->last_name = $request->last_name;
2548        }
2549
2550        // If user is invited then update status and delete invitation
2551        $userEmail = strtolower($user->email);
2552        $invitation = AdminUserInvitation::firstWhere('email', $userEmail);
2553        if ($invitation) {
2554            $user->status = "Active";
2555            $user->activation_date = Carbon::now()->toDateTimeString();
2556            $user->company_id = $invitation->company_id;
2557            $user->company_group_id = $invitation->company_group_id ?? $invitation->company_subgroup_id;
2558
2559            FlyMsgUserDailyUsage::where('user_id', $user->id)
2560                ->update([
2561                    'company_id' => $user->company_id,
2562                    'group_id'   => $user->company_group_id,
2563                    'user_status' => $user->status
2564                ]);
2565
2566            $user->unset('invited_to_company');
2567            $user->unset('invited_to_company_by_admin');
2568        }
2569
2570        $user->save();
2571        User::where('_id', $user->id)
2572            ->update([
2573                '$unset' => [
2574                    'temp_password' => 1,
2575                    'temp_password_expiry' => 1
2576                ]
2577            ]);
2578        if ($invitation) {
2579            $invitation->email = $userEmail;
2580            $invitation->delete();
2581        }
2582
2583        $data = [
2584            "first_name" => $user->first_name,
2585            "last_name" => $user->last_name,
2586            "email" => $userEmail,
2587            "do_not_send_welcome_notification" => true,
2588        ];
2589
2590        Registered::dispatch($user, $data);
2591
2592        return response()->json([
2593            'success' => true,
2594            'message' => "Your password has been changed successfully.",
2595        ], 200);
2596    }
2597
2598    public function export_csv_report(Request $request)
2599    {
2600        $filters = $request->filters;
2601        $users_ids = $request->users ? explode(',', $request->users) : [];
2602        return (new UsersReportExport($filters, $users_ids))->download('reporting-details-export.csv');
2603    }
2604
2605    public function export_csv_report_overview(Request $request)
2606    {
2607        $company_id = $request->company_id;
2608        return (new UsersReportOverviewExport($company_id))->download('reporting-overview-export.csv');
2609    }
2610
2611    public function export_csv_report_usage(Request $request)
2612    {
2613        // $admin = auth()->user();
2614        // $from_date = $request->fromDate;
2615        // $to_date = $request->toDate;
2616        // $user_ids = $request->user_ids ? explode(',', $request->user_ids) : [];
2617        // $group_ids = $request->group_ids ? explode(',', $request->group_ids) : [];
2618        // $subgroup_ids = $request->subgroup_ids ? explode(',', $request->subgroup_ids) : [];
2619
2620        // return (new AllUsersReportUsageExport($admin, $from_date, $to_date, $user_ids, $group_ids, $subgroup_ids))->download('reporting-usage-export.csv');
2621
2622        $company_id = $request->company_id;
2623        $from_date = $request->fromDate;
2624        $to_date = $request->toDate;
2625        $users_ids = $request->users_ids ? explode(',', $request->user_ids) : [];
2626        $group_ids = $request->group_ids ? explode(',', $request->group_ids) : [];
2627        $subgroup_ids = $request->subgroup_ids ? explode(',', $request->users) : [];
2628        return (new UsersReportUsageExport($company_id, $from_date, $to_date, $users_ids, $group_ids, $subgroup_ids))->download('reporting-usage-export.csv');
2629    }
2630
2631    public function remove_users_from_group(Request $request, $slug, CompanyGroup $company_group)
2632    {
2633        $user_ids = $request->users;
2634        if (!is_array($user_ids)) {
2635            throw new ExpectedException("You need to provide user ids in an array");
2636        }
2637
2638        $group = CompanyGroup::find($request->company_group_id);
2639        $this->adminUsersService->moveUsersToGroup($user_ids, $group);
2640
2641        return response()->json([
2642            'success' => true,
2643            'message' => "Users have been removed successfully from {$company_group->name}",
2644            'users' => $user_ids
2645        ], 200);
2646    }
2647
2648    public function user_info(Request $request)
2649    {
2650        $user = User::where('email', $request->email)->first();
2651        $subscription = $user->subscription('main');
2652        $plan = $subscription->plan;
2653
2654        return response()->json([
2655            'flymsg_id' => $user->id,
2656            'name' => $user->first_name . ' ' . $user->last_name,
2657            'plan' => $plan->title,
2658            'identifier' => $plan->identifier,
2659            'email' => $request->email,
2660            'status' => $subscription->stripe_status,
2661            'ends_at' => $subscription->ends_at,
2662            'is_trial' => $subscription->onTrial(),
2663        ], 200);
2664    }
2665}