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