22
33namespace App \Http \Controllers \Seller ;
44
5+ use App \Models \Shop ;
6+ use App \Models \Town ;
57use App \Models \User ;
8+ use App \Models \Image ;
9+ use App \Models \Quarter ;
610use Illuminate \Http \Request ;
11+ use Illuminate \Support \Facades \DB ;
12+ use Illuminate \Support \Facades \Log ;
713use App \Http \Controllers \Controller ;
814use Illuminate \Support \Facades \Auth ;
915use App \Http \Resources \SellerResource ;
16+ use Illuminate \Validation \Rule ;
17+ use Illuminate \Support \Facades \Storage ;
1018
1119class CurrentSellerController extends Controller
1220{
@@ -15,4 +23,197 @@ public function currentSeller(){
1523 $ user =Auth::guard ('api ' )->user ();
1624 return SellerResource::make (User::find ($ user ->id ));
1725 }
26+
27+ public function updateSeller (Request $ request ){
28+ $ user =Auth::guard ('api ' )->user ();
29+ $ seller = User::query ()->with (['shops ' , 'shops.images ' , 'shops.categories ' ])->findOrFail ($ user ->id );
30+ $ shop = $ seller ->shops ->first ();
31+
32+
33+ $ notEmpty = fn ($ v ) => !is_null ($ v ) && (!is_string ($ v ) || trim ($ v ) !== '' ); // garde 0/'0'
34+ $ onlyProvided = function (\Illuminate \Http \Request $ r , array $ keys ) use ($ notEmpty ) {
35+ return array_filter ($ r ->only ($ keys ), $ notEmpty );
36+ };
37+
38+
39+
40+
41+ try {
42+ // 1) Mise à jour vendeur
43+ $ seller ->fill ([
44+ 'firstName ' => $ request ->input ('firstName ' , $ seller ->firstName ),
45+ 'lastName ' => $ request ->input ('lastName ' , $ seller ->lastName ),
46+ 'email ' => $ request ->input ('email ' , $ seller ->email ),
47+ 'phone_number ' => $ request ->input ('phone_number ' , $ seller ->phone_number ),
48+ 'birthDate ' => $ request ->input ('birthDate ' , $ seller ->birthDate ),
49+ 'nationality ' => $ request ->input ('nationality ' , $ seller ->nationality ),
50+ ]);
51+
52+ DB ::transaction (function () use ($ request , $ seller , $ onlyProvided , $ notEmpty ) {
53+ // USER: update partiel sans null
54+ $ userData = $ onlyProvided ($ request , [
55+ 'firstName ' ,'lastName ' ,'email ' ,'phone_number ' ,'birthDate ' ,'nationality ' ,'isWholesaler '
56+ ]);
57+ if (!empty ($ userData )) {
58+ // caster isWholesaler si présent
59+ if (array_key_exists ('isWholesaler ' , $ userData )) {
60+ $ userData ['isWholesaler ' ] = (string )$ userData ['isWholesaler ' ];
61+ }
62+ $ seller ->update ($ userData );
63+ }
64+
65+ // FICHIERS USER
66+ if ($ request ->hasFile ('identity_card_in_front ' )) {
67+ $ seller ->identity_card_in_front = $ request ->file ('identity_card_in_front ' )->store ('cni/front ' ,'public ' );
68+ }
69+ if ($ request ->hasFile ('identity_card_in_back ' )) {
70+ $ seller ->identity_card_in_back = $ request ->file ('identity_card_in_back ' )->store ('cni/back ' ,'public ' );
71+ }
72+ if ($ request ->hasFile ('identity_card_with_the_person ' )) {
73+ $ seller ->identity_card_with_the_person = $ request ->file ('identity_card_with_the_person ' )->store ('cni/person ' ,'public ' );
74+ }
75+ $ seller ->save ();
76+
77+ // SHOP
78+ $ shop = $ seller ->shop ?: new Shop (['user_id ' => $ seller ->id ]);
79+
80+ $ shopData = $ onlyProvided ($ request , [
81+ 'shop_name ' ,'shop_description ' ,'product_type ' ,'town_id ' ,'quarter_id '
82+ ]);
83+
84+ if (array_key_exists ('product_type ' , $ shopData )) {
85+ $ shopData ['product_type ' ] = (string )$ shopData ['product_type ' ];
86+ }
87+
88+
89+ if (!empty ($ shopData )) {
90+ $ shop ->fill ($ shopData ); // fillable requis dans Shop
91+ }
92+
93+ // FICHIER SHOP PROFILE
94+ if ($ request ->hasFile ('shop_profile ' )) {
95+ $ shop ->shop_profile = $ request ->file ('shop_profile ' )->store ('shop/profile ' ,'public ' );
96+ }
97+
98+ // Localisation par nom (optionnel, uniquement si fourni et non vide)
99+ if ($ request ->filled ('town ' )) {
100+ $ town = \App \Models \Town::where ('town_name ' , $ request ->input ('town ' ))->first ();
101+ if ($ town ) $ shop ->town_id = $ town ->id ;
102+ }
103+ if ($ request ->filled ('quarter ' )) {
104+ $ quarter = \App \Models \Quarter::where ('quarter_name ' , $ request ->input ('quarter ' ))->first ();
105+ if ($ quarter ) $ shop ->quarter_id = $ quarter ->id ;
106+ }
107+
108+ $ shop ->save ();
109+
110+ // Catégories: sync seulement si fourni
111+ if ($ request ->has ('categories ' ) && is_array ($ request ->input ('categories ' ))) {
112+ $ ids = collect ($ request ->input ('categories ' ))
113+ ->map (fn ($ it ) => is_array ($ it ) ? ($ it ['id ' ] ?? $ it ['value ' ] ?? null ) : $ it )
114+ ->filter ()->unique ()->values ()->all ();
115+ $ shop ->categories ()->sync ($ ids );
116+ }
117+
118+ // Images: remplacer seulement si fichiers fournis
119+ if ($ request ->hasFile ('images ' )) {
120+ $ files = $ request ->file ('images ' );
121+ if (is_array ($ files ) && count ($ files ) > 0 ) {
122+ $ shop ->images ()->detach ();
123+ $ attach = [];
124+ foreach ($ files as $ f ) {
125+ $ img = new \App \Models \Image ();
126+ $ img ->image_path = $ f ->store ('shop/images ' ,'public ' );
127+ $ img ->save ();
128+ $ attach [] = $ img ->id ;
129+ }
130+ if ($ attach ) $ shop ->images ()->attach ($ attach );
131+ }
132+ }
133+ });
134+
135+ return response ()->json ([
136+ 'success ' => true ,
137+ 'message ' => 'Shop updated successfully ' ,
138+ ], 200 );
139+
140+ } catch (\Throwable $ e ) {
141+ DB ::rollBack ();
142+ Log::error ('Shop update error ' , ['error ' => $ e ->getMessage (), 'trace ' => $ e ->getTraceAsString ()]);
143+ return response ()->json ([
144+ 'success ' => false ,
145+ 'message ' => 'Something went wrong ' ,
146+ 'errors ' => $ e ->getMessage (),
147+ ], 500 );
148+ }
149+ }
150+
151+
152+ protected function storeMaybeBase64OrFile (Request $ request , string $ field , ?string $ existingPath , string $ diskPath ): ?string
153+ {
154+ // 1) fichier multipart
155+ if ($ request ->hasFile ($ field )) {
156+ $ file = $ request ->file ($ field );
157+ return $ file ->store ($ diskPath , 'public ' );
158+ }
159+
160+ // 2) base64 data URL string
161+ if ($ request ->filled ($ field ) && is_string ($ request ->input ($ field ))) {
162+ $ data = $ request ->input ($ field );
163+ if ($ this ->isDataUrl ($ data )) {
164+ return $ this ->storeBase64DataUrl ($ data , $ diskPath );
165+ }
166+ // Chaîne vide => suppression
167+ if ($ data === '' ) {
168+ return null ;
169+ }
170+ }
171+
172+ // sinon, on garde l’existant
173+ return $ existingPath ;
174+ }
175+
176+ /**
177+ * Variante générique pour un item qui peut être un UploadedFile (dans $request->images[])
178+ * ou une base64 string passée directement dans le tableau (cas JSON).
179+ */
180+ protected function storeMaybeBase64OrFileGeneric ($ value , string $ diskPath ): ?string
181+ {
182+ // UploadedFile
183+ if (is_object ($ value ) && method_exists ($ value , 'store ' )) {
184+ return $ value ->store ($ diskPath , 'public ' );
185+ }
186+ // base64 string
187+ if (is_string ($ value )) {
188+ if ($ this ->isDataUrl ($ value )) {
189+ return $ this ->storeBase64DataUrl ($ value , $ diskPath );
190+ }
191+ // sinon on ignore (non base64)
192+ }
193+ // objet {path: 'dataurl'} venant du front
194+ if (is_array ($ value ) && isset ($ value ['path ' ]) && is_string ($ value ['path ' ]) && $ this ->isDataUrl ($ value ['path ' ])) {
195+ return $ this ->storeBase64DataUrl ($ value ['path ' ], $ diskPath );
196+ }
197+ return null ;
198+ }
199+
200+ protected function isDataUrl (string $ value ): bool
201+ {
202+ return str_starts_with ($ value , 'data:image/ ' );
203+ }
204+
205+ protected function storeBase64DataUrl (string $ dataUrl , string $ diskPath ): string
206+ {
207+ // data:image/png;base64,XXXX
208+ [$ meta , $ content ] = explode (', ' , $ dataUrl , 2 );
209+ $ extension = 'png ' ;
210+ if (preg_match ('/data:image \\/( \\w+);base64/i ' , $ meta , $ m )) {
211+ $ extension = strtolower ($ m [1 ]);
212+ }
213+ $ binary = base64_decode ($ content );
214+ $ filename = $ diskPath .'/ ' .uniqid ('img_ ' ).'. ' .$ extension ;
215+ Storage::disk ('public ' )->put ($ filename , $ binary );
216+ return $ filename ;
217+ }
218+
18219}
0 commit comments