Skip to content

Commit 6509459

Browse files
committed
lead index migrate to react
1 parent 44b8e65 commit 6509459

4 files changed

Lines changed: 1370 additions & 159 deletions

File tree

app/Http/Controllers/Workflow/LeadsController.php

Lines changed: 166 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@
33
namespace App\Http\Controllers\Workflow;
44

55
use Illuminate\Support\Str;
6+
use App\Models\User;
67
use App\Models\Workflow\Leads;
78
use App\Services\LeadsKPIService;
89
use App\Traits\NextPreviousTrait;
910
use App\Services\SelectDataService;
1011
use App\Http\Controllers\Controller;
12+
use Illuminate\Http\Request;
1113
use Illuminate\Support\Facades\Auth;
1214
use App\Models\Workflow\Opportunities;
1315
use App\Http\Requests\Workflow\UpdateLeadRequest;
16+
use App\Models\Companies\CompaniesAddresses;
17+
use App\Models\Companies\CompaniesContacts;
1418

1519
class LeadsController extends Controller
1620
{
@@ -30,17 +34,169 @@ public function __construct(SelectDataService $SelectDataService,
3034
* @return \Illuminate\Contracts\View\View
3135
*/
3236
public function index()
33-
{
34-
// Using the OpportunitiesKPIService to retrieve KPI data
35-
$data['leadsCountRate'] = $this->leadsKPIService->getLeadsDataRate();
36-
$leadByCompany = $this->leadsKPIService->getLeadsByCompany();
37-
$leadsCount = $this->leadsKPIService->getLeadsCount();
38-
$leadsCountByUser = $this->leadsKPIService->getLeadsCountByUser();
37+
{
38+
$leadsCount = $this->leadsKPIService->getLeadsCount();
39+
$dataRate = $this->leadsKPIService->getLeadsDataRate();
40+
$leadByCompany = $this->leadsKPIService->getLeadsByCompany();
41+
$leadsCountByUser = $this->leadsKPIService->getLeadsCountByUser();
3942
$leadsCountByPriority = $this->leadsKPIService->getLeadsCountByPriority();
40-
return view('workflow/leads-index', array_merge(
41-
compact(
42-
'leadByCompany', 'leadsCount', 'leadsCountByUser', 'leadsCountByPriority')
43-
))->with('data', $data);
43+
44+
return view('workflow/leads-index', [
45+
'kpi' => ['count' => $leadsCount],
46+
'chart' => $dataRate->map(fn ($r) => [
47+
'statu' => $r->statu,
48+
'count' => $r->leadsCountRate,
49+
])->values()->all(),
50+
'byCompany' => $leadByCompany->map(fn ($o) => [
51+
'company_label' => $o->companie?->label ?? '',
52+
'company_url' => route('companies.show', ['id' => $o->companies_id]),
53+
'count' => $o->count,
54+
])->values()->all(),
55+
'byPriority' => $leadsCountByPriority->map(fn ($r) => [
56+
'priority' => $r->priority,
57+
'count' => $r->leadsCount,
58+
])->values()->all(),
59+
'byUser' => $leadsCountByUser->map(fn ($leads) => [
60+
'user_name' => $leads->first()->UserManagement?->name ?? '',
61+
'counts' => $leads->pluck('total', 'statu')->all(),
62+
])->values()->all(),
63+
]);
64+
}
65+
66+
// -------------------------------------------------------------------------
67+
// JSON endpoints for the React LeadsIndex component
68+
// -------------------------------------------------------------------------
69+
70+
public function listJson(Request $request)
71+
{
72+
$search = $request->get('search', '');
73+
$statuses = array_filter(array_map('intval', (array) $request->get('statuses', [])));
74+
$priorities = array_filter(array_map('intval', (array) $request->get('priorities', [])));
75+
$sortField = $request->get('sort', 'created_at');
76+
$sortAsc = $request->boolean('asc', false);
77+
$companyId = $request->get('company_id');
78+
79+
$allowed = ['source', 'campaign', 'priority', 'statu', 'created_at', 'companie'];
80+
if (!in_array($sortField, $allowed)) {
81+
$sortField = 'created_at';
82+
}
83+
84+
$dir = $sortAsc ? 'asc' : 'desc';
85+
$query = Leads::with(['companie:id,label,code', 'contact:id,first_name,name', 'UserManagement:id,name'])
86+
->when($search, fn ($q) => $q->where(fn ($q2) =>
87+
$q2->where('source', 'like', '%'.$search.'%')
88+
->orWhere('campaign', 'like', '%'.$search.'%')
89+
))
90+
->when($statuses, fn ($q) => $q->whereIn('statu', $statuses))
91+
->when($priorities, fn ($q) => $q->whereIn('priority', $priorities))
92+
->when($companyId, fn ($q) => $q->where('companies_id', $companyId));
93+
94+
match ($sortField) {
95+
'companie' => $query->orderByRaw("(SELECT label FROM companies WHERE companies.id = leads.companies_id) {$dir}"),
96+
default => $query->orderBy($sortField, $dir),
97+
};
98+
99+
$items = $query->paginate(15);
100+
101+
return response()->json([
102+
'data' => $items->map(fn ($l) => [
103+
'id' => $l->id,
104+
'source' => $l->source,
105+
'campaign' => $l->campaign,
106+
'priority' => $l->priority,
107+
'statu' => $l->statu,
108+
'created_at' => $l->created_at?->format('d/m/Y'),
109+
'companie' => $l->companie ? ['id' => $l->companie->id, 'label' => $l->companie->label] : null,
110+
'contact' => $l->contact ? ['id' => $l->contact->id, 'name' => trim($l->contact->first_name.' '.$l->contact->name)] : null,
111+
'user' => $l->UserManagement ? ['id' => $l->UserManagement->id, 'name' => $l->UserManagement->name] : null,
112+
'url' => route('leads.show', ['id' => $l->id]),
113+
]),
114+
'meta' => [
115+
'total' => $items->total(),
116+
'per_page' => $items->perPage(),
117+
'current_page' => $items->currentPage(),
118+
'last_page' => $items->lastPage(),
119+
],
120+
]);
121+
}
122+
123+
public function kanbanJson()
124+
{
125+
$items = Leads::with(['companie:id,label', 'contact:id,first_name,name', 'UserManagement:id,name'])->get();
126+
127+
return response()->json($items->map(fn ($l) => [
128+
'id' => $l->id,
129+
'source' => $l->source,
130+
'campaign' => $l->campaign,
131+
'priority' => $l->priority,
132+
'statu' => $l->statu,
133+
'companie' => $l->companie ? ['id' => $l->companie->id, 'label' => $l->companie->label] : null,
134+
'contact' => $l->contact ? ['id' => $l->contact->id, 'name' => trim($l->contact->first_name.' '.$l->contact->name)] : null,
135+
'user' => $l->UserManagement ? ['id' => $l->UserManagement->id, 'name' => $l->UserManagement->name] : null,
136+
'url' => route('leads.show', ['id' => $l->id]),
137+
]));
138+
}
139+
140+
public function kanbanMoveJson(Request $request, int $id)
141+
{
142+
abort_unless(auth()->check(), 403);
143+
$validated = $request->validate(['statu' => 'required|integer|between:1,5']);
144+
$lead = Leads::findOrFail($id);
145+
$lead->update(['statu' => $validated['statu']]);
146+
return response()->json(['ok' => true]);
147+
}
148+
149+
public function storeJson(Request $request)
150+
{
151+
abort_unless(auth()->check(), 403);
152+
153+
$validated = $request->validate([
154+
'companies_id' => 'required|integer',
155+
'companies_contacts_id' => 'required|integer',
156+
'companies_addresses_id' => 'required|integer',
157+
'user_id' => 'required|integer',
158+
'source' => 'required|string|max:255',
159+
'priority' => 'required|integer|between:1,4',
160+
'campaign' => 'nullable|string|max:255',
161+
'comment' => 'nullable|string',
162+
]);
163+
164+
$lead = Leads::create($validated);
165+
166+
return response()->json([
167+
'redirect' => route('leads.show', ['id' => $lead->id]),
168+
], 201);
169+
}
170+
171+
public function selectDataJson()
172+
{
173+
return response()->json([
174+
'companies' => $this->SelectDataService->getCompanies()->map(fn ($c) => [
175+
'id' => $c->id,
176+
'label' => $c->label ?? $c->last_name,
177+
'code' => $c->code,
178+
]),
179+
'users' => User::select('id', 'name')->get(),
180+
]);
181+
}
182+
183+
public function addressesJson(int $companyId)
184+
{
185+
return response()->json(
186+
CompaniesAddresses::select('id', 'label', 'adress')
187+
->where('companies_id', $companyId)
188+
->get()
189+
);
190+
}
191+
192+
public function contactsJson(int $companyId)
193+
{
194+
return response()->json(
195+
CompaniesContacts::select('id', 'first_name', 'name')
196+
->where('companies_id', $companyId)
197+
->get()
198+
->map(fn ($c) => ['id' => $c->id, 'name' => trim($c->first_name.' '.$c->name)])
199+
);
44200
}
45201

46202
/**

resources/js/app.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import KanbanBoard from './components/KanbanBoard.jsx';
88
import DocumentTable from './components/DocumentTable.jsx';
99
import NestingPage from './components/NestingPage.jsx';
1010
import QuotesIndex from './components/QuotesIndex.jsx';
11+
import OpportunitiesIndex from './components/OpportunitiesIndex.jsx';
12+
import LeadsIndex from './components/LeadsIndex.jsx';
1113
import CompaniesIndex from './components/CompaniesIndex.jsx';
1214
import OrdersIndex from './components/OrdersIndex.jsx';
1315
import DeliverysIndex from './components/DeliverysIndex.jsx';
@@ -137,6 +139,50 @@ function mountQuotesIndex() {
137139
);
138140
}
139141

142+
function mountLeadsIndex() {
143+
const element = document.getElementById('leads-index-app');
144+
if (!element) return;
145+
146+
const parse = (attr) => {
147+
try { return JSON.parse(element.dataset[attr] ?? 'null'); } catch { return null; }
148+
};
149+
150+
createRoot(element).render(
151+
React.createElement(LeadsIndex, {
152+
kpi: parse('kpi') ?? {},
153+
chart: parse('chart') ?? [],
154+
byCompany: parse('byCompany') ?? [],
155+
byPriority: parse('byPriority') ?? [],
156+
byUser: parse('byUser') ?? [],
157+
endpoints: parse('endpoints') ?? {},
158+
trans: parse('trans') ?? {},
159+
companieId: parse('companieId') ?? null,
160+
})
161+
);
162+
}
163+
164+
function mountOpportunitiesIndex() {
165+
const element = document.getElementById('opportunities-index-app');
166+
if (!element) return;
167+
168+
const parse = (attr) => {
169+
try { return JSON.parse(element.dataset[attr] ?? 'null'); } catch { return null; }
170+
};
171+
172+
createRoot(element).render(
173+
React.createElement(OpportunitiesIndex, {
174+
kpi: parse('kpi') ?? {},
175+
chart: parse('chart') ?? [],
176+
activities: parse('activities') ?? [],
177+
byCompany: parse('byCompany') ?? [],
178+
byAmount: parse('byAmount') ?? [],
179+
endpoints: parse('endpoints') ?? {},
180+
trans: parse('trans') ?? {},
181+
companieId: parse('companieId') ?? null,
182+
})
183+
);
184+
}
185+
140186
function mountOrdersIndex() {
141187
const element = document.getElementById('orders-index-app');
142188
if (!element) return;
@@ -401,6 +447,8 @@ mountCompaniesIndex();
401447
mountWhiteboard();
402448
mountNestingPage();
403449
mountQuotesIndex();
450+
mountLeadsIndex();
451+
mountOpportunitiesIndex();
404452
mountOrdersIndex();
405453
mountQuoteLinesIndex();
406454
mountOrderLinesIndex();

0 commit comments

Comments
 (0)