diff --git a/.gitignore b/.gitignore index d430557..de543e8 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ storage/crm_migration.csv MIG/errors_sql.txt public/js public/css +public/assets diff --git a/app/Enums/ApiError.php b/app/Enums/ApiError.php index 4b822d7..f381e49 100644 --- a/app/Enums/ApiError.php +++ b/app/Enums/ApiError.php @@ -95,9 +95,10 @@ class ApiError extends BaseEnumRoutable 'customerExists' => 'L\'utilisateur est déjà enregistré sur ce site', 'customerNotActivated' => 'Le compte n\'est pas activé', 'customerAlreadyActive' => 'Le compte est déjà activé', - 'singleOptinCustomerExists' => 'Le signle optin ne peut être ajouté car un compte existe.', - 'authFailed' => 'Echec de l\'authentification', + 'singleOptinCustomerExists' => 'Le single optin ne peut être ajouté car un compte existe.', + 'authFailed' => 'Echec de l\'authentification du compte', 'needAuth' => 'Vous devez être authentifié', + 'apiAuthFailed' => 'Echec de l\'authentification client à l\'Api LDC-CRM pour ce service', 'methodNotAllowed' => 'This method is not allowed for this request', 'wrongTimeStamp' => 'Your request is malformed, please check timestamp header and parameter', 'missingParameter' => 'The request is missing some parameters', diff --git a/app/Enums/CustomerExportType.php b/app/Enums/CustomerExportType.php new file mode 100644 index 0000000..89ce1c1 --- /dev/null +++ b/app/Enums/CustomerExportType.php @@ -0,0 +1,33 @@ + 1, + 'customer' => 2, + 'both' => 3 + ]; + } + public static function labels(): array + { + return [ + 'singleOptin' => trans('Les single optins uniquement'), + 'customer' => trans('Les clients uniquement acceptant de recevoir les newsletters'), + 'both' => trans('La totalité des client acceptant de recevoir les newsletters') + ]; + } +} diff --git a/app/Http/Controllers/AnswerController.php b/app/Http/Controllers/AnswerController.php new file mode 100644 index 0000000..976befe --- /dev/null +++ b/app/Http/Controllers/AnswerController.php @@ -0,0 +1,42 @@ +question; + if ($parent) { + $query->whereHas('question', function ($q) use ($parent) { + return $q->whereId($parent->id); + }); + } + return $query; + } + + public function index(CrudIndexRequest $request) + { + /** @var \Illuminate\View\View */ + $view = $this->crudIndex($request); + if ($request->ajax()) { + return $view; + } + return view('answer.index', $view->getData()); + } +} diff --git a/app/Http/Controllers/BrandController.php b/app/Http/Controllers/BrandController.php index 482f5d9..0be8700 100644 --- a/app/Http/Controllers/BrandController.php +++ b/app/Http/Controllers/BrandController.php @@ -3,29 +3,28 @@ namespace App\Http\Controllers; use App\Http\Controllers\Controller; -use App\Http\Requests\ManageBrandRequest; use App\Models\Brand; +use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest; +use Kwaadpepper\CrudPolicies\Traits\CrudController; class BrandController extends Controller { - public function index() - { - $brands = Brand::all(); - return view('brands.index', compact('brands')); + use CrudController { + index as crudIndex; } - public function manage(ManageBrandRequest $request, Brand $brand) - { - if ($request->isMethod('post')) { - if (!$brand) { - $brand = new Brand($request->validated()); - } else { - $brand->fill($request->validated()); - } - $brand->save(); - return redirect()->route('brands')->with('success', trans('Modifications enregistrées !')); - } + /** @var Brand */ + public static $modelClass = Brand::class; - return view('brands.manage', compact('brand')); + public static $layout = 'layouts.app'; + + public function index(CrudIndexRequest $request) + { + /** @var \Illuminate\View\View */ + $view = $this->crudIndex($request); + if ($request->ajax()) { + return $view; + } + return view('brand.index', $view->getData()); } } diff --git a/app/Http/Controllers/CustomerController.php b/app/Http/Controllers/CustomerController.php index 22e5f26..ef34a83 100644 --- a/app/Http/Controllers/CustomerController.php +++ b/app/Http/Controllers/CustomerController.php @@ -2,17 +2,108 @@ namespace App\Http\Controllers; +use App\Enums\CustomerExportType; +use App\Http\Requests\CustomerExport; use App\Models\Brand; use App\Models\Customer; use App\Models\CustomerInfo; use App\Models\CustomerLogin; +use App\Models\SingleOptin; +use Illuminate\Database\Query\JoinClause; +use Illuminate\Http\Request; +use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\Schema; +use Illuminate\Support\Facades\Session; +use Illuminate\Support\Str; +use League\Csv\Writer; +use Symfony\Component\HttpFoundation\StreamedResponse; class CustomerController extends Controller { - public function index() + public function index(Request $request) { - $brands = Brand::select('id', 'name')->get(); - return view('customers.index', compact('brands')); + $modelTable = (new Customer())->getTable(); + $modelClass = Customer::class; + $brands = Brand::select('id', 'name')->get(); + $columns = ['customer_infos.lastname', 'customer_infos.firstname']; + + // Jointure pour pouvoir trier les colonnes + /** @var \Illuminate\Database\Eloquent\Builder */ + $query = CustomerInfo::join('customer_logins', function (JoinClause $join) { + $join->on('customer_logins.brand_id', '=', 'customer_infos.brand_id') + ->on('customer_logins.customer_id', '=', 'customer_infos.customer_id'); + }) + ->join('customers', function (JoinClause $join) { + $join->on('customers.id', '=', 'customer_infos.customer_id'); + }) + ->join('brands', function (JoinClause $join) { + $join->on('brands.id', '=', 'customer_infos.brand_id'); + }); + if (request()->brand or Session::has("crud.$modelTable.brand")) { + $brand = $request->brand ?? Session::get("crud.$modelTable.brand"); + Session::put("crud.$modelTable.brand", $brand); + $query = $query->where('customer_infos.brand_id', $brand); + } + + // Search on crud Label column + if ($request->search or Session::has("crud.$modelTable.search")) { + $search = $request->search ?? Session::get("crud.$modelTable.search"); + Session::put("crud.$modelTable.search", $search); + $query->where(function ($q) use ($columns, $search) { + foreach ($columns as $column) { + $q = $q->orWhere($column, 'LIKE', "%$search%"); + } + $q = $q->orWhere('customers.email', 'LIKE', "%$search%"); + $q = $q->orWhere('customer_logins.last_connection', 'LIKE', "%$search%"); + }); + } + + // Sort columns + if ($request->sort_col) { + Session::put("crud.$modelTable.sort_col", $request->sort_col); + } + if ($request->sort_way) { + Session::put("crud.$modelTable.sort_way", $request->sort_way); + } + + if ($request->rst) { + Session::remove("crud.$modelTable.brand"); + Session::remove("crud.$modelTable.search"); + Session::remove("crud.$modelTable.sort_way"); + Session::remove("crud.$modelTable.sort_col"); + } + if ( + Session::has("crud.$modelTable.sort_col") and + Session::has("crud.$modelTable.sort_way") and + (Schema::hasColumn($modelTable, Session::get("crud.$modelTable.sort_col")) or + in_array(Session::get("crud.$modelTable.sort_col"), [ + 'brands.name', + 'customers.email', + 'customer_infos.firstname', + 'customer_infos.lastname', + 'customer_infos.opt_in', + 'customer_logins.last_connection', + 'customer_logins.status' + ])) + ) { + $query = $query->orderBy( + Session::get("crud.$modelTable.sort_col"), + Session::get("crud.$modelTable.sort_way") + ); + } + + /** @var \Illuminate\Pagination\AbstractPaginator */ + $customers = $query->paginate(config('crud.paginate', 50)); + + // use a crud controller (any) to gather crudModels + $modelsClasses = (new BrandController())->getCrudModels(); + return view('customer.index', compact( + 'modelsClasses', + 'modelClass', + 'modelTable', + 'customers', + 'brands' + )); } public function show(Customer $customer, Brand $brand) @@ -21,48 +112,14 @@ class CustomerController extends Controller ->where('brand_id', $brand->id)->firstOrFail(); $customerLogin = CustomerLogin::where('customer_id', $customer->id) ->where('brand_id', $brand->id)->first(); - return view('customers.show', compact('customerInfos', 'customerLogin')); - } - public function filter($texte, Brand $brand = null) - { - if ($brand) { - $customers = Customer::join('customer_infos', 'customers.id', '=', 'customer_infos.customer_id') - ->join('customer_logins', 'customers.id', '=', 'customer_logins.customer_id')->select( - 'customer_infos.customer_id', - 'customer_infos.firstname', - 'customer_infos.lastname', - 'customer_infos.opt_in', - 'customers.email', - 'customer_infos.brand_id', - 'customer_logins.last_connection' - )->where([ - ['lastname', 'like', '%' . $texte . '%'], - ['customer_infos.brand_id', $brand->id], - ['customer_logins.brand_id', $brand->id] - ])->orWhere([ - ['email', 'like', '%' . $texte . '%'], - ['customer_infos.brand_id', $brand->id], - ['customer_logins.brand_id', $brand->id] - ])->get(); - } else { - $customers = CustomerInfo::join('customers', 'customers.id', '=', 'customer_infos.customer_id') - ->join('customer_logins', function ($join) { - $join->on('customer_logins.customer_id', '=', 'customer_infos.customer_id'); - $join->on('customer_logins.brand_id', '=', 'customer_infos.brand_id'); - })->select( - 'customer_infos.customer_id', - 'customer_infos.firstname', - 'customer_infos.lastname', - 'customer_infos.opt_in', - 'customers.email', - 'customer_infos.brand_id', - 'customer_logins.last_connection' - )->where('lastname', 'like', '%' . $texte . '%') - ->orWhere('email', 'like', '%' . $texte . '%')->get(); - } - - return response()->json($customers); + // use a crud controller (any) to gather crudModels + $modelsClasses = (new BrandController())->getCrudModels(); + return view('customer.show', compact( + 'modelsClasses', + 'customerInfos', + 'customerLogin' + )); } public function delete(Customer $customer, Brand $brand) @@ -77,6 +134,104 @@ class CustomerController extends Controller $customer->delete(); } - return redirect()->route('customers')->with('success', "Compte supprimé."); + return redirect()->route('customers.index')->with('success', "Compte supprimé."); + } + + public function export() + { + // use a crud controller (any) to gather crudModels + $modelsClasses = (new BrandController())->getCrudModels(); + $brands = Brand::all(); + return view('customer.export', compact( + 'brands', + 'modelsClasses' + )); + } + + public function exportSubmit(CustomerExport $request) + { + $pagination = 2000; + $header = '"lastname";"firstname";"email";"hashcode"'; + + $w = Writer::createFromString($header . PHP_EOL); + $w->setDelimiter(';'); + $w->setEnclosure('"'); + $w->setOutputBOM(Writer::BOM_UTF8); + + $exportType = CustomerExportType::make(\intval($request->export_type)); + + //We send the CSV using Symfony StreamedResponse + $response = new StreamedResponse(); + $response->headers->set('Content-Encoding', 'none'); + $response->headers->set('Content-Type', 'text/csv; charset=UTF-8'); + $response->headers->set('Description', 'File Transfer'); + $response->headers->set( + 'Content-Disposition', + sprintf( + 'attachment; filename="Export pour newsletter %s %s.csv"', + Carbon::now()->format('d-m-Y_H-i'), + Str::slug($exportType) + ) + ); + + switch ($exportType) { + case CustomerExportType::both(): + $continue = true; + // continue + case CustomerExportType::customer(): + $i = 0; + /** @var \Illuminate\Database\Eloquent\Builder $req */ + $req = CustomerInfo::where('brand_id', $request->brand); + $total = $req->count(); + $pages = $total / $pagination; + do { + /** @var \Illuminate\Pagination\LengthAwarePaginator $items */ + $items = $req->with('customer', function ($q) { + $q->select(['id', 'email']); + })->paginate( + $pagination, + ['lastname', 'firstname', 'hashcode', 'customer_id'], + 'page', + $i + ); + $items->map(function (CustomerInfo $customerInfo) use ($w) { + $w->insertOne([ + 'lastname' => $customerInfo->lastname, + 'firstname' => $customerInfo->firstname, + 'email' => $customerInfo->customer->email, + 'hashcode' => $customerInfo->hashcode + ]); + }); + } while ($i++ <= $pages); + if (!isset($continue)) { + break; + } + // continue + case CustomerExportType::singleOptin(): + SingleOptin::where('brand_id', $request->brand)->get() + ->map(function (SingleOptin $singleOptin) use ($w) { + $w->insertOne([ + 'lastname' => '', + 'firstname' => '', + 'email' => $singleOptin->email, + 'hashcode' => '' + ]); + }); + break; + } + + //we create a callable to output the CSV in chunk + //with Symfony StreamResponse you can flush the body content if necessary + //see Symfony documentation for more information + $flush_threshold = 1000; //the flush value should depend on your CSV size. + $response->setCallback(function () use ($w, $flush_threshold) { + foreach ($w->chunk(1024) as $offset => $chunk) { + echo $chunk; + if ($offset % $flush_threshold === 0) { + flush(); + } + } + }); + return $response; } } diff --git a/app/Http/Controllers/LoginController.php b/app/Http/Controllers/LoginController.php index f7033f7..c1e18aa 100644 --- a/app/Http/Controllers/LoginController.php +++ b/app/Http/Controllers/LoginController.php @@ -21,7 +21,7 @@ class LoginController extends Controller $request->remember !== null ? true : false ) ) { - return redirect()->route('customers'); + return redirect()->route('customers.index'); } else { return back()->withInput($request->except("password")) ->withErrors("Les identifiants entrés sont incorrects, veuillez réessayer."); diff --git a/app/Http/Controllers/QuestionController.php b/app/Http/Controllers/QuestionController.php new file mode 100644 index 0000000..2d0284c --- /dev/null +++ b/app/Http/Controllers/QuestionController.php @@ -0,0 +1,125 @@ +crudIndex($request); + if ($request->ajax()) { + return $view; + } + return view('question.index', $view->getData()); + } + + public function indexQuery(Builder $query): Builder + { + if (request()->brand) { + $query = $query->where('brand_id', '=', request()->brand); + } + return $query; + } + + public function export() + { + $brands = Brand::all(); + return view('question.export', compact('brands')); + } + + public function exportSubmit(QuestionExport $request) + { + $results = []; + $brand = Brand::findOrFail($request->brand); + $questions = $brand->questions->load('answers'); + + foreach ($questions as $question) { + $answersCounts = DB::query() + ->selectRaw('count(*) as total, answer_id') + ->from('customer_answer') + ->whereIn('answer_id', $question->answers->pluck('id')) + ->groupBy('answer_id') + ->get()->keyBy('answer_id'); + + $results[$question->id] = [ + 'question' => $question->question, + 'answers' => [] + ]; + foreach ($question->answers as $answer) { + $results[$question->id]['answers'][] = + [ + "$answer->answer ", + $answersCounts[$answer->id]->total ?? 0 + ]; + } + } + + $pagination = 2000; + + $w = Writer::createFromString(''); + $w->setDelimiter(';'); + $w->setEnclosure('"'); + $w->setOutputBOM(Writer::BOM_UTF8); + + //We send the CSV using Symfony StreamedResponse + $response = new StreamedResponse(); + $response->headers->set('Content-Encoding', 'none'); + $response->headers->set('Content-Type', 'text/csv; charset=UTF-8'); + $response->headers->set('Description', 'File Transfer'); + $response->headers->set( + 'Content-Disposition', + sprintf( + 'attachment; filename="Export pour newsletter %s %s.csv"', + Carbon::now()->format('d-m-Y_H-i'), + Str::slug($brand->name) + ) + ); + + foreach ($results as $result) { + $w->insertOne([ + 'question' => $result['question'], + ]); + foreach ($result['answers'] as $answer) { + $w->insertOne($answer); + } + $w->insertOne([]); + } + + //we create a callable to output the CSV in chunk + //with Symfony StreamResponse you can flush the body content if necessary + //see Symfony documentation for more information + $flush_threshold = 1000; //the flush value should depend on your CSV size. + $response->setCallback(function () use ($w, $flush_threshold) { + foreach ($w->chunk(1024) as $offset => $chunk) { + echo $chunk; + if ($offset % $flush_threshold === 0) { + flush(); + } + } + }); + return $response; + } +} diff --git a/app/Http/Controllers/ServiceController.php b/app/Http/Controllers/ServiceController.php index 2d45863..98cdcff 100644 --- a/app/Http/Controllers/ServiceController.php +++ b/app/Http/Controllers/ServiceController.php @@ -2,49 +2,45 @@ namespace App\Http\Controllers; -use App\Http\Requests\ManageServiceRequest; -use App\Models\Brand; +use App\Http\Requests\GenerateApiToken; +use App\Mail\ServiceCredentialRenewed; use App\Models\Service; +use Illuminate\Support\Facades\Mail; +use Kwaadpepper\CrudPolicies\Http\Requests\CrudIndexRequest; +use Kwaadpepper\CrudPolicies\Traits\CrudController; class ServiceController extends Controller { - public function index() - { - $services = Service::all(); - return view('services.index', compact('services')); + use CrudController { + index as crudIndex; } - public function manage(ManageServiceRequest $request, Service $service = null) + /** @var Service */ + public static $modelClass = Service::class; + + public static $layout = 'layouts.app'; + + public function index(CrudIndexRequest $request) { - $brands = Brand::all(); - $edit = $service ? true : false; - - if ($request->isMethod('post')) { - if (!$service) { - $service = new Service($request->validated()); - } else { - $service->fill($request->validated()); - } - $brand = Brand::findOrFail($request->brand_id); - $service->brand()->associate($brand); - $service->save(); - - return redirect()->route('services')->with('success', $edit ? 'Modifications enregistrées !' : sprintf( - 'Token du service : \'%s\'', - $service->bearer_token - )); + /** @var \Illuminate\View\View */ + $view = $this->crudIndex($request); + if ($request->ajax()) { + return $view; } - - return view('services.manage', compact('service', 'brands', 'edit')); + return view('service.index', $view->getData()); } - public function generateApiToken(Service $service) + // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed + public function generateApiToken(GenerateApiToken $request, Service $service) { + /** @var \App\Models\User $user */ + $user = auth()->user(); $bearerToken = $service->generateBearerToken(); $bearerPwd = $service->bearer_pwd; $service->saveOrFail(); + Mail::send(new ServiceCredentialRenewed($service, $user)); return back() // phpcs:ignore Generic.Files.LineLength.TooLong - ->with('success', "Nouveau token d'API de $service->name : '$bearerToken' et mot de passe '$bearerPwd'"); + ->with('error', "ATTENTION : METTEZ À JOUR LE SITE ! \nNouveau token d'API de $service->name : '$bearerToken' et mot de passe '$bearerPwd'"); } } diff --git a/app/Http/Controllers/SingleOptinController.php b/app/Http/Controllers/SingleOptinController.php new file mode 100644 index 0000000..7174356 --- /dev/null +++ b/app/Http/Controllers/SingleOptinController.php @@ -0,0 +1,38 @@ +crudIndex($request); + if ($request->ajax()) { + return $view; + } + return view('single_optin.index', $view->getData()); + } + + public function indexQuery(Builder $query): Builder + { + if (request()->brand) { + $query = $query->where('brand_id', request()->brand); + } + return $query; + } +} diff --git a/app/Http/Controllers/SingleOptinsController.php b/app/Http/Controllers/SingleOptinsController.php deleted file mode 100644 index 303585d..0000000 --- a/app/Http/Controllers/SingleOptinsController.php +++ /dev/null @@ -1,37 +0,0 @@ -get(); - return view('single-optins.index', compact('brands')); - } - - public function filter($texte, $brandId = null) - { - if ($brandId !== null) { - $customers = SingleOptin::where([['email', 'like', '%' . $texte . '%'], ['brand_id', $brandId]])->get(); - } else { - $customers = SingleOptin::where('email', 'like', '%' . $texte . '%')->get(); - } - - return response()->json($customers); - } - - public function delete($id) - { - // TODO : Gestion avec les stats - $optin = SingleOptin::find($id); - if ($optin) { - $optin->delete(); - } - return new StatusResource(['status' => "OK"]); - } -} diff --git a/app/Http/Requests/CustomerExport.php b/app/Http/Requests/CustomerExport.php new file mode 100644 index 0000000..85b7c9d --- /dev/null +++ b/app/Http/Requests/CustomerExport.php @@ -0,0 +1,41 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'brand' => 'required|numeric|exists:brands,id', + 'export_type' => [ + 'required', + 'numeric', + // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed + function ($attribute, $value, $fail) { + if (!\in_array($value, CustomerExportType::values())) { + $fail(trans('Le type d\'export invalide')); + } + } + ] + ]; + } +} diff --git a/app/Http/Requests/GenerateApiToken.php b/app/Http/Requests/GenerateApiToken.php new file mode 100644 index 0000000..cecfde4 --- /dev/null +++ b/app/Http/Requests/GenerateApiToken.php @@ -0,0 +1,30 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + // + ]; + } +} diff --git a/app/Http/Requests/QuestionExport.php b/app/Http/Requests/QuestionExport.php new file mode 100644 index 0000000..8ef5ca7 --- /dev/null +++ b/app/Http/Requests/QuestionExport.php @@ -0,0 +1,30 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'brand' => 'required|numeric|exists:brands,id' + ]; + } +} diff --git a/app/Mail/ServiceCredentialRenewed.php b/app/Mail/ServiceCredentialRenewed.php new file mode 100644 index 0000000..5a32473 --- /dev/null +++ b/app/Mail/ServiceCredentialRenewed.php @@ -0,0 +1,55 @@ +service = $service; + $this->user = $user; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('mail.service-renewed') + ->subject('!!! Warning !!!, New service credential have been generated !') + ->text('mail.service-renewed-plain') + ->with('appName', config('app.name')) + ->with('service', $this->service) + ->with('by', sprintf('%s %s (%s)', $this->user->firstname, $this->user->lastname, $this->user->email)) + ->to( + config('mail.contactsList.serviceweb', 'equipe.web@ldc.fr'), + sprintf('%s service warning', config('app.name')) + ); + } +} diff --git a/app/Models/Answer.php b/app/Models/Answer.php index f85e234..6ce9028 100644 --- a/app/Models/Answer.php +++ b/app/Models/Answer.php @@ -4,15 +4,45 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Str; +use Kwaadpepper\CrudPolicies\Enums\CrudAction; +use Kwaadpepper\CrudPolicies\Enums\CrudType; +use Kwaadpepper\CrudPolicies\Traits\IsCrudModel; class Answer extends Model { use HasFactory; + use IsCrudModel; + + protected $crudLabelColumn = 'answer'; + + protected $crudValueColumn = 'id'; protected $fillable = [ 'answer' ]; + public function __construct(array $attributes = []) + { + self::$editableProperties = [ + 'answer' => [ + 'label' => Str::ucfirst(trans('models.common.answer')), + 'type' => CrudType::string(), + 'validate' => [ + 'min:1', + 'max:255' + ], + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view(), + CrudAction::create(), + CrudAction::update() + ] + ] + ]; + parent::__construct($attributes); + } + /** * Question BelongsTo relation * diff --git a/app/Models/Brand.php b/app/Models/Brand.php index d80fae1..32ce105 100644 --- a/app/Models/Brand.php +++ b/app/Models/Brand.php @@ -4,13 +4,22 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Str; +use Kwaadpepper\CrudPolicies\Enums\CrudAction; +use Kwaadpepper\CrudPolicies\Enums\CrudType; +use Kwaadpepper\CrudPolicies\Traits\IsCrudModel; use Rennokki\QueryCache\Traits\QueryCacheable; class Brand extends Model { + use IsCrudModel; use HasFactory; use QueryCacheable; + protected $crudLabelColumn = 'name'; + + protected $crudValueColumn = 'id'; + protected $cacheFor = 0; protected $fillable = [ @@ -20,6 +29,34 @@ class Brand extends Model public function __construct(array $attributes = []) { $this->cacheFor = config('api.servicesDBCache') * 60; + + self::$editableProperties = [ + 'name' => [ + 'label' => Str::ucfirst(trans('models.common.name')), + 'type' => CrudType::string(), + 'validate' => [ + 'min:5', + 'max:255' + ], + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view(), + CrudAction::create(), + CrudAction::update() + ] + ], + 'services' => [ + 'label' => Str::ucfirst(Str::plural(trans('models.classes.services'))), + 'type' => CrudType::belongsToMany(), + 'belongsToMany' => Service::class, + 'belongsToManyLabel' => 'name', + 'actions' => [ + CrudAction::view(), + CrudAction::create(), + CrudAction::update(), + ] + ] + ]; parent::__construct($attributes); } diff --git a/app/Models/CustomerInfo.php b/app/Models/CustomerInfo.php index a47f6c0..e657fc6 100644 --- a/app/Models/CustomerInfo.php +++ b/app/Models/CustomerInfo.php @@ -100,6 +100,16 @@ class CustomerInfo extends Model return $this->belongsTo(Customer::class); } + /** + * get Login + * + * @return \App\Models\CustomerLogin + */ + public function login() + { + return $this->customer->login($this->brand); + } + /** * Brand BelongsTo relation * diff --git a/app/Models/Question.php b/app/Models/Question.php index e69f3e0..1b6dacd 100644 --- a/app/Models/Question.php +++ b/app/Models/Question.php @@ -5,12 +5,21 @@ namespace App\Models; use App\Enums\QuestionType; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Str; +use Kwaadpepper\CrudPolicies\Enums\CrudAction; +use Kwaadpepper\CrudPolicies\Enums\CrudType; +use Kwaadpepper\CrudPolicies\Traits\IsCrudModel; use Kwaadpepper\Enum\Traits\CastsEnums; class Question extends Model { use CastsEnums; use HasFactory; + use IsCrudModel; + + protected $crudLabelColumn = 'question'; + + protected $crudValueColumn = 'id'; protected $enumCasts = [ 'type' => QuestionType::class @@ -21,6 +30,57 @@ class Question extends Model 'type' ]; + public function __construct(array $attributes = []) + { + self::$editableProperties = [ + 'question' => [ + 'label' => Str::ucfirst(trans('models.common.question')), + 'type' => CrudType::string(), + 'validate' => [ + 'min:10', + 'max:255' + ], + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view(), + CrudAction::create(), + CrudAction::update() + ] + ], + 'type' => [ + 'label' => Str::ucfirst(trans('models.common.type')), + 'type' => CrudType::enum(), + 'enum' => QuestionType::class, + 'actions' => [ + CrudAction::view(), + CrudAction::create(), + CrudAction::update(), + ] + ], + 'brand_id' => [ + 'label' => Str::ucfirst(trans('models.classes.brand')), + 'type' => CrudType::belongsTo(), + 'belongsTo' => Brand::class, + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view(), + CrudAction::create(), + CrudAction::update(), + ] + ], + 'answers' => [ + 'label' => Str::ucfirst(Str::plural(trans('models.classes.answers'))), + 'type' => CrudType::belongsToMany(), + 'belongsToMany' => Answer::class, + 'belongsToManyLabel' => 'answer', + 'actions' => [ + CrudAction::view() + ] + ] + ]; + parent::__construct($attributes); + } + /** * Brand BelongsTo relation * diff --git a/app/Models/Service.php b/app/Models/Service.php index fc571de..b358d7b 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -8,13 +8,21 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Str; +use Kwaadpepper\CrudPolicies\Enums\CrudAction; +use Kwaadpepper\CrudPolicies\Enums\CrudType; +use Kwaadpepper\CrudPolicies\Traits\IsCrudModel; use Rennokki\QueryCache\Traits\QueryCacheable; class Service extends Model { + use IsCrudModel; use HasFactory; use QueryCacheable; + protected $crudLabelColumn = 'name'; + + protected $crudValueColumn = 'id'; + protected $cacheFor = 0; protected $fillable = [ @@ -24,6 +32,32 @@ class Service extends Model public function __construct(array $attributes = []) { $this->cacheFor = config('api.servicesDBCache') * 60; + + self::$editableProperties = [ + 'name' => [ + 'label' => Str::ucfirst(trans('models.common.name')), + 'type' => CrudType::string(), + 'validate' => [ + 'min:5', + 'max:255' + ], + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view(), + CrudAction::create(), + CrudAction::update() + ] + ], + 'brand_id' => [ + 'label' => Str::ucfirst(trans('models.classes.brand')), + 'type' => CrudType::belongsTo(), + 'belongsTo' => Brand::class, + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view() + ] + ], + ]; parent::__construct($attributes); } diff --git a/app/Models/SingleOptin.php b/app/Models/SingleOptin.php index 7776219..ea9ede0 100644 --- a/app/Models/SingleOptin.php +++ b/app/Models/SingleOptin.php @@ -4,15 +4,76 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Str; +use Kwaadpepper\CrudPolicies\Enums\CrudAction; +use Kwaadpepper\CrudPolicies\Enums\CrudType; +use Kwaadpepper\CrudPolicies\Traits\IsCrudModel; class SingleOptin extends Model { use HasFactory; + use IsCrudModel; + + protected $crudLabelColumn = 'email'; + + protected $crudValueColumn = 'id'; protected $fillable = [ 'email' ]; + public function __construct(array $attributes = []) + { + self::$editableProperties = [ + 'email' => [ + 'label' => Str::ucfirst(trans('models.common.email')), + 'type' => CrudType::email(), + 'validate' => [ + 'required', + 'email:rfc,dns', + // @phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed + function ($attribute, $value, $fail) { + $q = static::query(); + if (request()->user) { + $q = $q->where('id', '!=', $this->id); + } + if ($q->where('email', $value)->exists()) { + $fail(__(':attribute est déjà utilisé', [ + 'attribute' => $attribute + ])); + } + } + ], + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view(), + CrudAction::create(), + CrudAction::update() + ] + ], + 'brand_id' => [ + 'label' => Str::ucfirst(trans('models.classes.brand')), + 'type' => CrudType::belongsTo(), + 'belongsTo' => Brand::class, + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view() + ] + ], + 'created_at' => [ + 'label' => Str::ucfirst(trans('models.common.optinDate')), + 'type' => CrudType::string(), + 'readonly' => true, + 'actions' => [ + CrudAction::viewAny(), + CrudAction::view(), + CrudAction::update() + ] + ], + ]; + parent::__construct($attributes); + } + /** * Brand BelongsTo relation * diff --git a/app/Policies/AnswerPolicy.php b/app/Policies/AnswerPolicy.php new file mode 100644 index 0000000..c38607e --- /dev/null +++ b/app/Policies/AnswerPolicy.php @@ -0,0 +1,29 @@ +policies = [ + 'answer' => [ + 'viewAny' => USR::make('everyOne'), + 'update' => USR::make('everyOne'), + 'create' => USR::make('everyOne'), + 'delete' => USR::make('everyOne') + ] + ]; + } +} diff --git a/app/Policies/BrandPolicy.php b/app/Policies/BrandPolicy.php new file mode 100644 index 0000000..02579b1 --- /dev/null +++ b/app/Policies/BrandPolicy.php @@ -0,0 +1,28 @@ +policies = [ + 'brand' => [ + 'viewAny' => USR::make('everyOne'), + 'update' => USR::make('everyOne'), + 'create' => USR::make('everyOne') + ] + ]; + } +} diff --git a/app/Policies/CustomerPolicy.php b/app/Policies/CustomerPolicy.php index 32e33ee..3eea775 100644 --- a/app/Policies/CustomerPolicy.php +++ b/app/Policies/CustomerPolicy.php @@ -4,12 +4,33 @@ namespace App\Policies; use App\Models\Customer; use App\Models\Service; +use App\Policies\Rules\UserStaticRules as USR; use Illuminate\Auth\Access\HandlesAuthorization; +use Kwaadpepper\CrudPolicies\Policies\RootPolicy; -class CustomerPolicy +class CustomerPolicy extends RootPolicy { use HandlesAuthorization; + /** + * Init policies on call + * + * @return void + */ + public function setPolicies() + { + /** + * This first rule to return true in a policy action authorises the action + */ + $this->policies = [ + 'customer' => [ + 'viewAny' => USR::make('everyOne'), + 'view' => USR::make('everyOne'), + 'delete' => USR::make('everyOne') + ] + ]; + } + public function customerBelongsToService(Service $service, Customer $customer) { return !\is_null($customer->login($service->brand)); diff --git a/app/Policies/QuestionPolicy.php b/app/Policies/QuestionPolicy.php new file mode 100644 index 0000000..ee18d37 --- /dev/null +++ b/app/Policies/QuestionPolicy.php @@ -0,0 +1,30 @@ +policies = [ + 'question' => [ + 'viewAny' => USR::make('everyOne'), + 'view' => USR::make('everyOne'), + 'update' => USR::make('everyOne'), + 'create' => USR::make('everyOne'), + 'delete' => USR::make('everyOne') + ] + ]; + } +} diff --git a/app/Policies/Rules/UserStaticRules.php b/app/Policies/Rules/UserStaticRules.php new file mode 100644 index 0000000..e68624c --- /dev/null +++ b/app/Policies/Rules/UserStaticRules.php @@ -0,0 +1,17 @@ +policies = [ + 'service' => [ + 'viewAny' => USR::make('everyOne'), + 'view' => USR::make('everyOne'), + 'update' => USR::make('everyOne'), + 'create' => USR::make('everyOne') + ] + ]; + } +} diff --git a/app/Policies/SingleOptinPolicy.php b/app/Policies/SingleOptinPolicy.php new file mode 100644 index 0000000..a47161b --- /dev/null +++ b/app/Policies/SingleOptinPolicy.php @@ -0,0 +1,27 @@ +policies = [ + 'singleoptin' => [ + 'viewAny' => USR::make('everyOne'), + 'delete' => USR::make('everyOne') + ] + ]; + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index df4b423..73af49a 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -3,7 +3,11 @@ namespace App\Providers; use Illuminate\Http\Resources\Json\JsonResource; +use Illuminate\Pagination\Paginator; +use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\URL; +use Illuminate\Support\Facades\View; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider @@ -31,5 +35,14 @@ class AppServiceProvider extends ServiceProvider if (!in_array(config('app.env'), ['local', 'testing'])) { URL::forceScheme('https'); } + + Paginator::useBootstrap(); + + $appInfos = Cache::remember('composer', 360, function () { + return json_decode(File::get(\app_path('../composer.json'))); + }); + View::share('name', $appInfos->name); + View::share('version', $appInfos->version); + View::share('license', $appInfos->license); } } diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index c0b3794..fe05944 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -2,8 +2,13 @@ namespace App\Providers; +use App\Models\Answer; +use App\Models\Brand; use App\Models\Customer; use App\Models\CustomerInfo; +use App\Models\Question; +use App\Models\Service; +use App\Models\SingleOptin; use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; @@ -36,6 +41,12 @@ class RouteServiceProvider extends ServiceProvider Route::middleware('web')->namespace($this->namespace)->group(base_path('routes/web.php')); }); + Route::model('brand', Brand::class); + Route::model('service', Service::class); + Route::model('single_optin', SingleOptin::class); + Route::model('question', Question::class); + Route::model('answer', Answer::class); + Route::bind('customer', function ($value) { if (\ctype_digit($value)) { $customer = Customer::where('id', '=', $value)->firstOrFail(); diff --git a/clients/V2 b/clients/V2 index b208c78..b29fb6a 160000 --- a/clients/V2 +++ b/clients/V2 @@ -1 +1 @@ -Subproject commit b208c78b97e68c078345620a5a023186a1753ee8 +Subproject commit b29fb6a5bc1a2740c3ce5276ff1d38199eed539c diff --git a/composer.json b/composer.json index 15400c8..b4fc2b5 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "ldc/ldccrmv2client", "type": "project", - "version": "2.1.5", + "version": "2.1.7", "description": "LDC CRM V2", "authors": [ { @@ -32,11 +32,14 @@ "fideloper/proxy": "^4.4", "fruitcake/laravel-cors": "^2.0", "guzzlehttp/guzzle": "^7.0.1", + "kwaadpepper/crud-policies": "^0.1.17", "kwaadpepper/enum": "^2.0", "laravel-lang/lang": "~7.0", "laravel/framework": "^8.39", "laravel/tinker": "^2.5", - "rennokki/laravel-eloquent-query-cache": "^3.0" + "league/csv": "^9.7", + "rennokki/laravel-eloquent-query-cache": "^3.0", + "spatie/laravel-mix-preload": "^1.2" }, "require-dev": { "facade/ignition": "^2.5", @@ -81,6 +84,7 @@ "prefer-stable": true, "scripts": { "test": [ + "echo 'check memcached is running';netcat -z localhost 11211", "@configclear", "./test.sh" ], diff --git a/composer.lock b/composer.lock index 39cc9e3..146429d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0df11a64ace2bcbbbc3710af5cc6868f", + "content-hash": "52ddf0e771e6661178474f2a87aeaf7e", "packages": [ { "name": "arondeparon/laravel-request-sanitizer", @@ -128,16 +128,16 @@ }, { "name": "brick/math", - "version": "0.9.2", + "version": "0.9.3", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0" + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", - "reference": "dff976c2f3487d42c1db75a3b180e2b9f0e72ce0", + "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", "shasum": "" }, "require": { @@ -147,7 +147,7 @@ "require-dev": { "php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", - "vimeo/psalm": "4.3.2" + "vimeo/psalm": "4.9.2" }, "type": "library", "autoload": { @@ -172,15 +172,19 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.9.2" + "source": "https://github.com/brick/math/tree/0.9.3" }, "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/brick/math", "type": "tidelift" } ], - "time": "2021-01-20T22:51:39+00:00" + "time": "2021-08-15T20:50:18+00:00" }, { "name": "cache/adapter-common", @@ -447,16 +451,16 @@ }, { "name": "composer/package-versions-deprecated", - "version": "1.11.99.2", + "version": "1.11.99.3", "source": { "type": "git", "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c" + "reference": "fff576ac850c045158a250e7e27666e146e78d18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/c6522afe5540d5fc46675043d3ed5a45a740b27c", - "reference": "c6522afe5540d5fc46675043d3ed5a45a740b27c", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/fff576ac850c045158a250e7e27666e146e78d18", + "reference": "fff576ac850c045158a250e7e27666e146e78d18", "shasum": "" }, "require": { @@ -500,7 +504,7 @@ "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", "support": { "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.2" + "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.3" }, "funding": [ { @@ -516,7 +520,7 @@ "type": "tidelift" } ], - "time": "2021-05-24T07:46:03+00:00" + "time": "2021-08-17T13:49:14+00:00" }, { "name": "doctrine/cache", @@ -1167,6 +1171,124 @@ ], "time": "2020-12-29T14:50:06+00:00" }, + { + "name": "facade/flare-client-php", + "version": "1.8.1", + "source": { + "type": "git", + "url": "https://github.com/facade/flare-client-php.git", + "reference": "47b639dc02bcfdfc4ebb83de703856fa01e35f5f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facade/flare-client-php/zipball/47b639dc02bcfdfc4ebb83de703856fa01e35f5f", + "reference": "47b639dc02bcfdfc4ebb83de703856fa01e35f5f", + "shasum": "" + }, + "require": { + "facade/ignition-contracts": "~1.0", + "illuminate/pipeline": "^5.5|^6.0|^7.0|^8.0", + "php": "^7.1|^8.0", + "symfony/http-foundation": "^3.3|^4.1|^5.0", + "symfony/mime": "^3.4|^4.0|^5.1", + "symfony/var-dumper": "^3.4|^4.0|^5.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.14", + "phpunit/phpunit": "^7.5.16", + "spatie/phpunit-snapshot-assertions": "^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "Facade\\FlareClient\\": "src" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Send PHP errors to Flare", + "homepage": "https://github.com/facade/flare-client-php", + "keywords": [ + "exception", + "facade", + "flare", + "reporting" + ], + "support": { + "issues": "https://github.com/facade/flare-client-php/issues", + "source": "https://github.com/facade/flare-client-php/tree/1.8.1" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2021-05-31T19:23:29+00:00" + }, + { + "name": "facade/ignition-contracts", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/facade/ignition-contracts.git", + "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/3c921a1cdba35b68a7f0ccffc6dffc1995b18267", + "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^v2.15.8", + "phpunit/phpunit": "^9.3.11", + "vimeo/psalm": "^3.17.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Facade\\IgnitionContracts\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://flareapp.io", + "role": "Developer" + } + ], + "description": "Solution contracts for Ignition", + "homepage": "https://github.com/facade/ignition-contracts", + "keywords": [ + "contracts", + "flare", + "ignition" + ], + "support": { + "issues": "https://github.com/facade/ignition-contracts/issues", + "source": "https://github.com/facade/ignition-contracts/tree/1.0.2" + }, + "time": "2020-10-16T08:27:54+00:00" + }, { "name": "fideloper/proxy", "version": "4.4.1", @@ -1606,6 +1728,70 @@ }, "time": "2021-06-30T20:03:07+00:00" }, + { + "name": "kwaadpepper/crud-policies", + "version": "0.1.17", + "source": { + "type": "git", + "url": "https://github.com/Kwaadpepper/crud-policies.git", + "reference": "0cd52413f9ee2f95b2ebc2d2d4621cfc2a104e47" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Kwaadpepper/crud-policies/zipball/0cd52413f9ee2f95b2ebc2d2d4621cfc2a104e47", + "reference": "0cd52413f9ee2f95b2ebc2d2d4621cfc2a104e47", + "shasum": "" + }, + "require": { + "facade/flare-client-php": "^1.8", + "illuminate/support": "~7|~8", + "kwaadpepper/enum": "^2.0", + "laravel/framework": "~7|~8" + }, + "require-dev": { + "orchestra/testbench": "^6.13", + "phpunit/phpunit": "~9.0", + "slevomat/coding-standard": "^7.0", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Kwaadpepper\\CrudPolicies\\Providers\\CrudPoliciesServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Kwaadpepper\\CrudPolicies\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jérémy Munsch", + "email": "github@jeremydev.ovh", + "homepage": "https://jeremydev.ovh" + } + ], + "description": "Makes CRUD easy, make policies easy and everyone happy", + "homepage": "https://github.com/kwaadpepper/crud-policies", + "keywords": [ + "Scafolding", + "crud", + "laravel", + "policies" + ], + "support": { + "issues": "https://github.com/Kwaadpepper/crud-policies/issues", + "source": "https://github.com/Kwaadpepper/crud-policies/tree/0.1.17" + }, + "time": "2021-09-10T14:23:18+00:00" + }, { "name": "kwaadpepper/enum", "version": "2.0.0", @@ -1708,16 +1894,16 @@ }, { "name": "laravel/framework", - "version": "v8.53.1", + "version": "v8.56.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "5df423c2790f32b26baee90518bb659572aa404f" + "reference": "d700f336dc672dcbfe46db05d4e5fe9347b3a5b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/5df423c2790f32b26baee90518bb659572aa404f", - "reference": "5df423c2790f32b26baee90518bb659572aa404f", + "url": "https://api.github.com/repos/laravel/framework/zipball/d700f336dc672dcbfe46db05d4e5fe9347b3a5b6", + "reference": "d700f336dc672dcbfe46db05d4e5fe9347b3a5b6", "shasum": "" }, "require": { @@ -1790,7 +1976,7 @@ "illuminate/view": "self.version" }, "require-dev": { - "aws/aws-sdk-php": "^3.186.4", + "aws/aws-sdk-php": "^3.189.0", "doctrine/dbal": "^2.6|^3.0", "filp/whoops": "^2.8", "guzzlehttp/guzzle": "^6.5.5|^7.0.1", @@ -1803,7 +1989,7 @@ "symfony/cache": "^5.1.4" }, "suggest": { - "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.186.4).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.189.0).", "brianium/paratest": "Required to run tests in parallel (^6.0).", "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6|^3.0).", "ext-ftp": "Required to use the Flysystem FTP driver.", @@ -1872,7 +2058,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-08-05T14:04:08+00:00" + "time": "2021-08-24T13:46:30+00:00" }, { "name": "laravel/tinker", @@ -2044,17 +2230,101 @@ "time": "2021-07-17T17:13:23+00:00" }, { - "name": "league/flysystem", - "version": "1.1.4", + "name": "league/csv", + "version": "9.7.1", "source": { "type": "git", - "url": "https://github.com/thephpleague/flysystem.git", - "reference": "f3ad69181b8afed2c9edf7be5a2918144ff4ea32" + "url": "https://github.com/thephpleague/csv.git", + "reference": "0ec57e8264ec92565974ead0d1724cf1026e10c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/f3ad69181b8afed2c9edf7be5a2918144ff4ea32", - "reference": "f3ad69181b8afed2c9edf7be5a2918144ff4ea32", + "url": "https://api.github.com/repos/thephpleague/csv/zipball/0ec57e8264ec92565974ead0d1724cf1026e10c1", + "reference": "0ec57e8264ec92565974ead0d1724cf1026e10c1", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "friendsofphp/php-cs-fixer": "^2.16", + "phpstan/phpstan": "^0.12.0", + "phpstan/phpstan-phpunit": "^0.12.0", + "phpstan/phpstan-strict-rules": "^0.12.0", + "phpunit/phpunit": "^9.5" + }, + "suggest": { + "ext-dom": "Required to use the XMLConverter and or the HTMLConverter classes", + "ext-iconv": "Needed to ease transcoding CSV using iconv stream filters" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Csv\\": "src" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://github.com/nyamsprod/", + "role": "Developer" + } + ], + "description": "CSV data manipulation made easy in PHP", + "homepage": "http://csv.thephpleague.com", + "keywords": [ + "convert", + "csv", + "export", + "filter", + "import", + "read", + "transform", + "write" + ], + "support": { + "docs": "https://csv.thephpleague.com", + "issues": "https://github.com/thephpleague/csv/issues", + "rss": "https://github.com/thephpleague/csv/releases.atom", + "source": "https://github.com/thephpleague/csv" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2021-04-17T16:32:08+00:00" + }, + { + "name": "league/flysystem", + "version": "1.1.5", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "18634df356bfd4119fe3d6156bdb990c414c14ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/18634df356bfd4119fe3d6156bdb990c414c14ea", + "reference": "18634df356bfd4119fe3d6156bdb990c414c14ea", "shasum": "" }, "require": { @@ -2127,7 +2397,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/1.1.4" + "source": "https://github.com/thephpleague/flysystem/tree/1.1.5" }, "funding": [ { @@ -2135,7 +2405,7 @@ "type": "other" } ], - "time": "2021-06-23T21:56:05+00:00" + "time": "2021-08-17T13:49:42+00:00" }, { "name": "league/mime-type-detection", @@ -2291,16 +2561,16 @@ }, { "name": "nesbot/carbon", - "version": "2.51.1", + "version": "2.52.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922" + "reference": "369c0e2737c56a0f39c946dd261855255a6fccbe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922", - "reference": "8619c299d1e0d4b344e1f98ca07a1ce2cfbf1922", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/369c0e2737c56a0f39c946dd261855255a6fccbe", + "reference": "369c0e2737c56a0f39c946dd261855255a6fccbe", "shasum": "" }, "require": { @@ -2381,7 +2651,7 @@ "type": "tidelift" } ], - "time": "2021-07-28T13:16:28+00:00" + "time": "2021-08-14T19:10:52+00:00" }, { "name": "nikic/php-parser", @@ -3181,16 +3451,16 @@ }, { "name": "ramsey/uuid", - "version": "4.1.1", + "version": "4.2.1", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "cd4032040a750077205918c86049aa0f43d22947" + "reference": "fe665a03df4f056aa65af552a96e1976df8c8dae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/cd4032040a750077205918c86049aa0f43d22947", - "reference": "cd4032040a750077205918c86049aa0f43d22947", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/fe665a03df4f056aa65af552a96e1976df8c8dae", + "reference": "fe665a03df4f056aa65af552a96e1976df8c8dae", "shasum": "" }, "require": { @@ -3204,26 +3474,26 @@ "rhumsaa/uuid": "self.version" }, "require-dev": { - "codeception/aspect-mock": "^3", - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7.0", + "captainhook/captainhook": "^5.10", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "doctrine/annotations": "^1.8", - "goaop/framework": "^2", + "ergebnis/composer-normalize": "^2.15", "mockery/mockery": "^1.3", "moontoast/math": "^1.1", "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.2", "php-mock/php-mock-mockery": "^1.3", - "php-mock/php-mock-phpunit": "^2.5", "php-parallel-lint/php-parallel-lint": "^1.1", - "phpbench/phpbench": "^0.17.1", + "phpbench/phpbench": "^1.0", "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^0.12", "phpstan/phpstan-mockery": "^0.12", "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^8.5", - "psy/psysh": "^0.10.0", - "slevomat/coding-standard": "^6.0", + "phpunit/phpunit": "^8.5 || ^9", + "slevomat/coding-standard": "^7.0", "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "3.9.4" + "vimeo/psalm": "^4.9" }, "suggest": { "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", @@ -3236,7 +3506,10 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-main": "4.x-dev" + }, + "captainhook": { + "force-install": true } }, "autoload": { @@ -3252,7 +3525,6 @@ "MIT" ], "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", - "homepage": "https://github.com/ramsey/uuid", "keywords": [ "guid", "identifier", @@ -3260,16 +3532,19 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "rss": "https://github.com/ramsey/uuid/releases.atom", - "source": "https://github.com/ramsey/uuid" + "source": "https://github.com/ramsey/uuid/tree/4.2.1" }, "funding": [ { "url": "https://github.com/ramsey", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" } ], - "time": "2020-08-18T17:17:46+00:00" + "time": "2021-08-11T01:06:55+00:00" }, { "name": "rennokki/laravel-eloquent-query-cache", @@ -3336,6 +3611,74 @@ ], "time": "2021-07-17T17:42:40+00:00" }, + { + "name": "spatie/laravel-mix-preload", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-mix-preload.git", + "reference": "b89dc366fa8a714ecb3d6af836db3c038795a3b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-mix-preload/zipball/b89dc366fa8a714ecb3d6af836db3c038795a3b6", + "reference": "b89dc366fa8a714ecb3d6af836db3c038795a3b6", + "shasum": "" + }, + "require": { + "illuminate/support": "^6.0|^7.0|^8.0", + "php": "^7.2.5|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.0|^9.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\MixPreload\\MixPreloadServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\MixPreload\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sebastian De Deyne", + "email": "sebastian@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Add preload and prefetch links based your Mix manifest", + "homepage": "https://github.com/spatie/laravel-mix-preload", + "keywords": [ + "laravel-mix-preload", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-mix-preload/issues", + "source": "https://github.com/spatie/laravel-mix-preload/tree/1.2.2" + }, + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + }, + { + "url": "https://www.patreon.com/spatie", + "type": "patreon" + } + ], + "time": "2021-01-04T08:01:50+00:00" + }, { "name": "swiftmailer/swiftmailer", "version": "v6.2.7", @@ -6072,83 +6415,18 @@ ], "time": "2020-11-10T18:47:58+00:00" }, - { - "name": "facade/flare-client-php", - "version": "1.8.1", - "source": { - "type": "git", - "url": "https://github.com/facade/flare-client-php.git", - "reference": "47b639dc02bcfdfc4ebb83de703856fa01e35f5f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facade/flare-client-php/zipball/47b639dc02bcfdfc4ebb83de703856fa01e35f5f", - "reference": "47b639dc02bcfdfc4ebb83de703856fa01e35f5f", - "shasum": "" - }, - "require": { - "facade/ignition-contracts": "~1.0", - "illuminate/pipeline": "^5.5|^6.0|^7.0|^8.0", - "php": "^7.1|^8.0", - "symfony/http-foundation": "^3.3|^4.1|^5.0", - "symfony/mime": "^3.4|^4.0|^5.1", - "symfony/var-dumper": "^3.4|^4.0|^5.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.14", - "phpunit/phpunit": "^7.5.16", - "spatie/phpunit-snapshot-assertions": "^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-4": { - "Facade\\FlareClient\\": "src" - }, - "files": [ - "src/helpers.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Send PHP errors to Flare", - "homepage": "https://github.com/facade/flare-client-php", - "keywords": [ - "exception", - "facade", - "flare", - "reporting" - ], - "support": { - "issues": "https://github.com/facade/flare-client-php/issues", - "source": "https://github.com/facade/flare-client-php/tree/1.8.1" - }, - "funding": [ - { - "url": "https://github.com/spatie", - "type": "github" - } - ], - "time": "2021-05-31T19:23:29+00:00" - }, { "name": "facade/ignition", - "version": "2.11.2", + "version": "2.12.0", "source": { "type": "git", "url": "https://github.com/facade/ignition.git", - "reference": "7c4e7a7da184cd00c7ce6eacc590200bb9672de7" + "reference": "74dcc32a2895a126d1e5f2cd3bbab499cac66db1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition/zipball/7c4e7a7da184cd00c7ce6eacc590200bb9672de7", - "reference": "7c4e7a7da184cd00c7ce6eacc590200bb9672de7", + "url": "https://api.github.com/repos/facade/ignition/zipball/74dcc32a2895a126d1e5f2cd3bbab499cac66db1", + "reference": "74dcc32a2895a126d1e5f2cd3bbab499cac66db1", "shasum": "" }, "require": { @@ -6211,60 +6489,7 @@ "issues": "https://github.com/facade/ignition/issues", "source": "https://github.com/facade/ignition" }, - "time": "2021-07-20T14:01:22+00:00" - }, - { - "name": "facade/ignition-contracts", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/facade/ignition-contracts.git", - "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/3c921a1cdba35b68a7f0ccffc6dffc1995b18267", - "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267", - "shasum": "" - }, - "require": { - "php": "^7.3|^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^v2.15.8", - "phpunit/phpunit": "^9.3.11", - "vimeo/psalm": "^3.17.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "Facade\\IgnitionContracts\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "homepage": "https://flareapp.io", - "role": "Developer" - } - ], - "description": "Solution contracts for Ignition", - "homepage": "https://github.com/facade/ignition-contracts", - "keywords": [ - "contracts", - "flare", - "ignition" - ], - "support": { - "issues": "https://github.com/facade/ignition-contracts/issues", - "source": "https://github.com/facade/ignition-contracts/tree/1.0.2" - }, - "time": "2020-10-16T08:27:54+00:00" + "time": "2021-08-24T09:53:54+00:00" }, { "name": "fakerphp/faker", @@ -6585,16 +6810,16 @@ }, { "name": "nunomaduro/collision", - "version": "v5.6.0", + "version": "v5.8.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "0122ac6b03c75279ef78d1c0ad49725dfc52a8d2" + "reference": "0c3c393462eada1233513664e2d22bb9f69ca393" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/0122ac6b03c75279ef78d1c0ad49725dfc52a8d2", - "reference": "0122ac6b03c75279ef78d1c0ad49725dfc52a8d2", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/0c3c393462eada1233513664e2d22bb9f69ca393", + "reference": "0c3c393462eada1233513664e2d22bb9f69ca393", "shasum": "" }, "require": { @@ -6606,7 +6831,7 @@ "require-dev": { "brianium/paratest": "^6.1", "fideloper/proxy": "^4.4.1", - "friendsofphp/php-cs-fixer": "^2.17.3", + "friendsofphp/php-cs-fixer": "^3.0", "fruitcake/laravel-cors": "^2.0.3", "laravel/framework": "^8.0 || ^9.0", "nunomaduro/larastan": "^0.6.2", @@ -6669,7 +6894,7 @@ "type": "patreon" } ], - "time": "2021-07-26T20:39:06+00:00" + "time": "2021-08-13T14:23:01+00:00" }, { "name": "phar-io/manifest", @@ -8567,16 +8792,16 @@ }, { "name": "slevomat/coding-standard", - "version": "7.0.13", + "version": "7.0.14", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "122a9bf9a4a2195f74100f47dfb8375982f43cc9" + "reference": "15b2b4630c148775debea8e412bc7e128d9868a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/122a9bf9a4a2195f74100f47dfb8375982f43cc9", - "reference": "122a9bf9a4a2195f74100f47dfb8375982f43cc9", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/15b2b4630c148775debea8e412bc7e128d9868a3", + "reference": "15b2b4630c148775debea8e412bc7e128d9868a3", "shasum": "" }, "require": { @@ -8587,12 +8812,12 @@ }, "require-dev": { "phing/phing": "2.16.4", - "php-parallel-lint/php-parallel-lint": "1.3.0", - "phpstan/phpstan": "0.12.93", + "php-parallel-lint/php-parallel-lint": "1.3.1", + "phpstan/phpstan": "0.12.96", "phpstan/phpstan-deprecation-rules": "0.12.6", - "phpstan/phpstan-phpunit": "0.12.21", - "phpstan/phpstan-strict-rules": "0.12.10", - "phpunit/phpunit": "7.5.20|8.5.5|9.5.7" + "phpstan/phpstan-phpunit": "0.12.22", + "phpstan/phpstan-strict-rules": "0.12.11", + "phpunit/phpunit": "7.5.20|8.5.5|9.5.8" }, "type": "phpcodesniffer-standard", "extra": { @@ -8612,7 +8837,7 @@ "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/7.0.13" + "source": "https://github.com/slevomat/coding-standard/tree/7.0.14" }, "funding": [ { @@ -8624,7 +8849,7 @@ "type": "tidelift" } ], - "time": "2021-07-29T14:30:22+00:00" + "time": "2021-08-26T12:17:56+00:00" }, { "name": "squizlabs/php_codesniffer", diff --git a/config/app.php b/config/app.php index 5bdde92..ea1878b 100644 --- a/config/app.php +++ b/config/app.php @@ -227,7 +227,11 @@ return [ 'View' => Illuminate\Support\Facades\View::class, 'Carbon' => Illuminate\Support\Carbon::class, 'ArcadiaMailType' => App\Enums\ArcadiaMailType::class, - 'ArcadiaOrderType' => App\Enums\ArcadiaOrderType::class + 'ArcadiaOrderType' => App\Enums\ArcadiaOrderType::class, + 'CustomerExportType' => App\Enums\CustomerExportType::class, + 'Brand' => App\Models\Brand::class, + 'Customer' => App\Models\Customer::class, + 'Answer' => App\Models\Answer::class, ], ]; diff --git a/package.json b/package.json index e329706..5df4967 100644 --- a/package.json +++ b/package.json @@ -2,28 +2,27 @@ "private": true, "scripts": { "dev": "npm run development", - "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --config=node_modules/laravel-mix/setup/webpack.config.js", - "watch": "npm run development -- --watch", - "watch-poll": "npm run watch -- --watch-poll", - "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --disable-host-check --config=node_modules/laravel-mix/setup/webpack.config.js", + "development": "mix", + "watch": "mix watch", + "watch-poll": "mix watch -- --watch-options-poll=1000", + "hot": "mix watch --hot", "prod": "npm run production", - "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --config=node_modules/laravel-mix/setup/webpack.config.js" + "production": "mix --production" }, "devDependencies": { - "axios": "^0.19", - "bootstrap": "^4.5.0", - "cross-env": "^7.0", - "jquery": "^3.2", - "laravel-mix": "^5.0.1", - "lodash": "^4.17.19", - "popper.js": "^1.12", - "resolve-url-loader": "^3.1.0", - "sass-loader": "^8.0.2", - "vue-template-compiler": "^2.6.12" - }, - "dependencies": { + "axios": "^0.21", + "clean-webpack-plugin": "^4.0.0-alpha.0", + "laravel-mix": "^6.0.6", + "laravel-mix-polyfill": "^3.0.0", "moment": "^2.29.1", - "sass": "^1.28.0", - "vue": "^2.6.12" + "postcss": "^8.1.14", + "postcss-discard-comments": "^4.0.2", + "resolve-url-loader": "^3.1.3", + "sass": "^1.32.11", + "sass-loader": "^11.0.1", + "swiper": "^6.6.1", + "vue": "^2.6.12", + "vue-loader": "^15.9.6", + "vue-template-compiler": "^2.6.12" } } diff --git a/public/js/app.js.LICENSE.txt b/public/js/app.js.LICENSE.txt deleted file mode 100644 index 953a26d..0000000 --- a/public/js/app.js.LICENSE.txt +++ /dev/null @@ -1,18 +0,0 @@ -/*! - * Vue.js v2.6.12 - * (c) 2014-2020 Evan You - * Released under the MIT License. - */ - -/** - * @license - * Lodash - * Copyright OpenJS Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ - -//! moment.js - -//! moment.js locale configuration diff --git a/public/mix-manifest.json b/public/mix-manifest.json index 2d60117..6784ee9 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -1,4 +1,4 @@ { - "/js/app.js": "/js/app.js", - "/css/app.css": "/css/app.css" + "/js/preload-back.js": "/js/preload-back.js", + "/css/preload-back.css": "/css/preload-back.css" } diff --git a/public/images/logo_ldc.png b/resources/assets/images/logo_ldc.png similarity index 100% rename from public/images/logo_ldc.png rename to resources/assets/images/logo_ldc.png diff --git a/resources/js/Components/SearchOptin.vue b/resources/js/Components/SearchOptin.vue deleted file mode 100644 index 62c361b..0000000 --- a/resources/js/Components/SearchOptin.vue +++ /dev/null @@ -1,101 +0,0 @@ - - - diff --git a/resources/js/Components/SearchUser.vue b/resources/js/Components/SearchUser.vue deleted file mode 100644 index 2aa9470..0000000 --- a/resources/js/Components/SearchUser.vue +++ /dev/null @@ -1,87 +0,0 @@ - - - diff --git a/resources/js/app.js b/resources/js/app.js deleted file mode 100644 index 4c6aeb6..0000000 --- a/resources/js/app.js +++ /dev/null @@ -1,17 +0,0 @@ -require('./bootstrap'); -import moment from 'moment'; - -window.Vue = require('vue'); - -Vue.filter('formatDate', function(value) { - if (value) { - return moment(String(value)).format('DD/MM/YYYY H:mm') - } -}); - -Vue.component('search-user', require('./Components/SearchUser.vue').default); -Vue.component('search-optin', require('./Components/SearchOptin.vue').default); - -const app = new Vue({ - el: '#app', -}); diff --git a/resources/js/back.js b/resources/js/back.js new file mode 100644 index 0000000..7c36abb --- /dev/null +++ b/resources/js/back.js @@ -0,0 +1,5 @@ +require('./bootstrap'); + +require('./pages/customer.delete') +require('./pages/service.index') +require('./pages/single_optin.index') diff --git a/resources/js/pages/customer.delete.js b/resources/js/pages/customer.delete.js new file mode 100644 index 0000000..4d9674d --- /dev/null +++ b/resources/js/pages/customer.delete.js @@ -0,0 +1,34 @@ +let customerDelete = document.getElementById('customerDelete'); + +if (customerDelete) { + customerDelete.addEventListener('submit', (e) => { + let self = e.target + e.preventDefault() + Swal.fire({ + title: 'Supprimer ce client pour cette marque ?', + text: 'Attention cette action est irréversible, si le client n\'appartient plus à aucune marque il sera complètement retiré des bases', + icon: 'warning', + confirmButtonText: 'Je comprends le danger et suis conscient de ce que je fait', + showCancelButton: true, + cancelButtonText: 'Annuler', + confirmButtonColor: '#dc3545' + }).then((result) => { + if (result.isConfirmed) { + Swal.fire({ + title: 'Attention au conséquences', + html: 'La supression de ce compte dans la crm n\'entrainera pas ça supression dans MESBR ni dans le front cache DB (pour les sites WPCRM).

Une fois le compte supprimé je ne pourrai plus récupérer le hashcode nécessaire pour effectuer ces opérations.

', + icon: 'info', + confirmButtonText: 'Je comprends le danger et suis conscient que celà aura des conséquences', + showCancelButton: true, + cancelButtonText: 'Annuler', + confirmButtonColor: '#dc3545' + }).then((result) => { + if (result.isConfirmed) { + self.submit() + } + }) + } + }) + }) +} + diff --git a/resources/js/pages/service.index.js b/resources/js/pages/service.index.js new file mode 100644 index 0000000..61a816d --- /dev/null +++ b/resources/js/pages/service.index.js @@ -0,0 +1,36 @@ +let genForms = document.getElementsByClassName('genToken'); + +if (genForms.length) { + for (let form of genForms) { + form.addEventListener('submit', (e) => { + let self = e.target + e.preventDefault() + Swal.fire({ + title: 'Regénérer un token ?', + text: 'Attention la regeneration empêchera le service de fonctionner tant que son token n\'aura pas été mis à jour', + icon: 'warning', + confirmButtonText: 'Je comprends le danger et suis conscient de ce que je fait', + showCancelButton: true, + cancelButtonText: 'Annuler', + confirmButtonColor: '#dc3545' + }).then((result) => { + if (result.isConfirmed) { + Swal.fire({ + title: 'Vous allez régénérer un token de service en production', + html: '

Je suis conscient que celà va avoir des implications et qu\'il me faudra mettre à jour le bearer token du service concerné dans son envirronement actuel

', + icon: 'info', + confirmButtonText: 'Oui, feu patate !!', + showCancelButton: true, + cancelButtonText: 'Annuler', + confirmButtonColor: '#dc3545' + }).then((result) => { + if (result.isConfirmed) { + self.submit() + } + }) + } + }) + }) + } +} + diff --git a/resources/js/pages/single_optin.index.js b/resources/js/pages/single_optin.index.js new file mode 100644 index 0000000..112407f --- /dev/null +++ b/resources/js/pages/single_optin.index.js @@ -0,0 +1,10 @@ +let brandSelect = document.getElementById('brandSelect'); +if (brandSelect) { + brandSelect.addEventListener('change', function (e) { + if (brandSelect.value !== '0') { + const url = new URL(location.href); + url.searchParams.set('brand', brandSelect.value); + location.assign(url.search); + } + }); +} diff --git a/resources/lang/en/models.php b/resources/lang/en/models.php new file mode 100644 index 0000000..ff61fae --- /dev/null +++ b/resources/lang/en/models.php @@ -0,0 +1,27 @@ + [ + 'services' => 'Services', + 'brands' => 'Brands', + 'brand' => 'Brand', + 'customers' => 'Customers', + 'questions' => 'Questions', + 'answers' => 'Answers', + 'singleoptins' => 'Single Opt-ins' + ], + 'common' => [ + 'title' => 'Title', + 'name' => 'Name', + 'email' => 'Email', + 'content' => 'Content', + 'visibility' => 'Visibility', + 'published' => 'Published', + 'group' => 'Group', + 'default' => 'Default', + 'optinDate' => 'Date opt-in', + 'question' => 'Question', + 'answer' => 'Answer', + 'type' => 'Type' + ] +]; diff --git a/resources/lang/fr/models.php b/resources/lang/fr/models.php new file mode 100644 index 0000000..1c38697 --- /dev/null +++ b/resources/lang/fr/models.php @@ -0,0 +1,27 @@ + [ + 'services' => 'Services', + 'brands' => 'Marques', + 'brand' => 'Marque', + 'questions' => 'Questions', + 'answers' => 'Réponses', + 'customers' => 'Clients', + 'singleoptins' => 'Opt-ins uniques' + ], + 'common' => [ + 'title' => 'Titre', + 'name' => 'Nom', + 'email' => 'E-mail', + 'content' => 'Contenu', + 'visibility' => 'Visibilitée', + 'published' => 'Publié', + 'group' => 'Groupe', + 'default' => 'Par défaut', + 'optinDate' => 'Date opt-in', + 'question' => 'Question', + 'type' => 'Type', + 'answer' => 'Réponse' + ] +]; diff --git a/resources/sass/_dashboard.scss b/resources/sass/_dashboard.scss deleted file mode 100644 index 0a6abdb..0000000 --- a/resources/sass/_dashboard.scss +++ /dev/null @@ -1,103 +0,0 @@ -body { - font-size: .875rem; -} - -.feather { - width: 16px; - height: 16px; - vertical-align: text-bottom; -} - -/* - * Sidebar - */ - -.sidebar { - position: fixed; - top: 0; - bottom: 0; - left: 0; - z-index: 100; /* Behind the navbar */ - padding: 48px 0 0; /* Height of navbar */ - box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1); -} - -@media (max-width: 767.98px) { - .sidebar { - top: 5rem; - } -} - -.sidebar-sticky { - position: relative; - top: 0; - height: calc(100vh - 48px); - padding-top: .5rem; - overflow-x: hidden; - overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ -} - -@supports ((position: -webkit-sticky) or (position: sticky)) { - .sidebar-sticky { - position: -webkit-sticky; - position: sticky; - } -} - -.sidebar .nav-link { - font-weight: 500; - color: #333; -} - -.sidebar .nav-link .feather { - margin-right: 4px; - color: #999; -} - -.sidebar .nav-link.active { - color: #007bff; -} - -.sidebar .nav-link:hover .feather, -.sidebar .nav-link.active .feather { - color: inherit; -} - -.sidebar-heading { - font-size: .75rem; - text-transform: uppercase; -} - -/* - * Navbar - */ - -.navbar-brand { - padding-top: .75rem; - padding-bottom: .75rem; - font-size: 1rem; - background-color: rgba(0, 0, 0, .25); - box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25); -} - -.navbar .navbar-toggler { - top: .25rem; - right: 1rem; -} - -.navbar .form-control { - padding: .75rem 1rem; - border-width: 0; - border-radius: 0; -} - -.form-control-dark { - color: #fff; - background-color: rgba(255, 255, 255, .1); - border-color: rgba(255, 255, 255, .1); -} - -.form-control-dark:focus { - border-color: transparent; - box-shadow: 0 0 0 3px rgba(255, 255, 255, .25); -} diff --git a/resources/sass/_layout.scss b/resources/sass/_layout.scss new file mode 100644 index 0000000..4b2e2f3 --- /dev/null +++ b/resources/sass/_layout.scss @@ -0,0 +1,17 @@ +.bodyFull { + margin: 0 !important; + padding: 0 !important; + min-height: calc(100vh - #{$navBarHeight} - #{$footerHeight}); +} + +#app { + & > .navbar { + height: $navBarHeight; + } + #footer { + height: $footerHeight; + padding: 0 !important; + color: $body-bg; + background-color: $footerBgColor; + } +} diff --git a/resources/sass/_variables.scss b/resources/sass/_variables.scss index 5af6218..b5d70bc 100644 --- a/resources/sass/_variables.scss +++ b/resources/sass/_variables.scss @@ -22,3 +22,7 @@ $theme-colors: ( "primary": #3176C4, "secondary": #E7374B ); + +$navBarHeight: 4rem; +$footerHeight: 3rem; +$footerBgColor: #161616; diff --git a/resources/sass/app.scss b/resources/sass/app.scss deleted file mode 100644 index 71428e3..0000000 --- a/resources/sass/app.scss +++ /dev/null @@ -1,10 +0,0 @@ -// Fonts -@import url('https://fonts.googleapis.com/css?family=Nunito'); - -// Variables -@import 'variables'; - -// Bootstrap -@import '~bootstrap/scss/bootstrap'; - -@import "dashboard"; diff --git a/resources/sass/back.scss b/resources/sass/back.scss new file mode 100644 index 0000000..55e4403 --- /dev/null +++ b/resources/sass/back.scss @@ -0,0 +1,5 @@ +// Variables +@import 'variables'; +@import 'layout'; + +@import "pages/login"; diff --git a/resources/sass/pages/login.scss b/resources/sass/pages/login.scss new file mode 100644 index 0000000..79f3d3c --- /dev/null +++ b/resources/sass/pages/login.scss @@ -0,0 +1,54 @@ +.bd-placeholder-img { + font-size: 1.125rem; + text-anchor: middle; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +@media (min-width: 768px) { + .bd-placeholder-img-lg { + font-size: 3.5rem; + } +} +div.login { + height: 100%; + display: -ms-flexbox; + display: flex; + -ms-flex-align: center; + align-items: center; + padding-top: 40px; + padding-bottom: 40px; + background-color: #f5f5f5; +} + +.form-signin { + width: 100%; + max-width: 330px; + padding: 15px; + margin: auto; +} +.form-signin .checkbox { + font-weight: 400; +} +.form-signin .form-control { + position: relative; + box-sizing: border-box; + height: auto; + padding: 10px; + font-size: 16px; +} +.form-signin .form-control:focus { + z-index: 2; +} +.form-signin input[type="email"] { + margin-bottom: -1px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.form-signin input[type="password"] { + margin-bottom: 10px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} diff --git a/resources/views/answer/index.blade.php b/resources/views/answer/index.blade.php new file mode 100644 index 0000000..e7d898f --- /dev/null +++ b/resources/views/answer/index.blade.php @@ -0,0 +1,119 @@ +@extends($viewLayout) + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ @include('crud-policies::crud.modules.breadcrumb', ['action' => CrudAction::viewAny()]) + @include('crud-policies::crud.modules.actionbar.bar', ['action' => CrudAction::viewAny()]) +
+
+
+
+ {{ $models->links() }} +
+
+
+
+ + + + {{ __('crud-policies::crud.reset') }} + +
+
+
+
+
+

{{ request()->question->question }}

+
+ + + @include('crud-policies::crud.modules.sorter') + + + @if(count($models)) + + {{-- INIT QUERIES for OPTIMIZING --}} + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if($prop['type']->equals(CrudType::order())) + @php ${"$modelTable$fieldName"} = $modelClass::max($fieldName); @endphp + @endif + @if($prop['type']->equals(CrudType::belongsTo())) + @php try { $models->load(Str::singular((new $prop['belongsTo']())->getTable())); } catch(\Exception $e) {} @endphp + @endif + @if($prop['type']->equals(CrudType::belongsToMany())) + @php $models->load("$fieldName"); @endphp + @endif + @endforeach + + {{-- DISPLAY MODELS --}} + @foreach($models as $model) + + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if(in_array(CrudAction::viewAny(), $prop['actions'])) + @switch($prop['type']) + @case(CrudType::belongsToMany() and $prop['belongsToMany'] === \App\Models\Project::class) + + @break + @case(CrudType::password()) + {{-- Ignore --}} + @break + @default + + @endswitch + @endif + @endforeach + + {{-- MODEL ACTIONS --}} + + + @endforeach + @else + + + + @endif + +
+ @foreach($model->{$fieldName} as $pSite) + {{ $pSite->{$prop['belongsToManyLabel']} }} + @endforeach + @include('crud-policies::crud.printfield', [ + 'action' => CrudAction::viewAny(), + 'field' => $model->{$fieldName}, + 'props' => $prop, + "$modelTable$fieldName" => ${"$modelTable$fieldName"} ?? null + ]) +
+ @can('view', $model) + {{ __('crud-policies::crud.view') }} + @endcan + @can('update', $model) + {{ __('crud-policies::crud.edit') }} + @endcan + @can('delete', $model) +
+ @csrf + @method('DELETE') + +
+ @endcan +
+
+ {{ __('crud-policies::crud.nothingtoshow') }} +
+ {{ $models->links() }} +
+
+
{{ $models->links() }}
+
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/brand/index.blade.php b/resources/views/brand/index.blade.php new file mode 100644 index 0000000..5d0906c --- /dev/null +++ b/resources/views/brand/index.blade.php @@ -0,0 +1,158 @@ +@extends($viewLayout) + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ @include('crud-policies::crud.modules.breadcrumb', ['action' => CrudAction::viewAny()]) + @include('crud-policies::crud.modules.actionbar.bar', ['action' => CrudAction::viewAny()]) +
+
+
+
+
+
+ + + + @if(request()->brand) + + @endif + {{ __('crud-policies::crud.reset') }} + +
+
+
+
+ + + + @foreach ($modelClass::getEditableProperties() as $colname => $prop) + @if(in_array(CrudAction::viewAny(), $prop['actions'])) + @switch($prop['type']) + @case(CrudType::password()) + {{-- Ignore --}} + @break + @default + + @endswitch + @endif + @endforeach + + + + + + + + @if(count($models)) + + {{-- INIT QUERIES for OPTIMIZING --}} + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if($prop['type']->equals(CrudType::order())) + @php ${"$modelTable$fieldName"} = $modelClass::max($fieldName); @endphp + @endif + @if($prop['type']->equals(CrudType::belongsTo())) + @php try { $models->load(Str::singular((new $prop['belongsTo']())->getTable())); } catch(\Exception $e) {} @endphp + @endif + @if($prop['type']->equals(CrudType::belongsToMany())) + @php $models->load("$fieldName"); @endphp + @endif + @endforeach + + {{-- DISPLAY MODELS --}} + @foreach($models as $model) + + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if(in_array(CrudAction::viewAny(), $prop['actions'])) + @switch($prop['type']) + @case(CrudType::belongsToMany() and $prop['belongsToMany'] === \App\Models\Project::class) + + @break + @case(CrudType::password()) + {{-- Ignore --}} + @break + @default + + @endswitch + @endif + @endforeach + + {{-- INFO COLS --}} + + + + + {{-- MODEL ACTIONS --}} + + + @endforeach + @else + + + + @endif + +
+ {{ $prop['label'] }} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + {{ __('Nombre de comptes')}} + + {{ __('Nombre d\'optins')}} + + {{ __('Date d\'ajout en base')}} + + @if(session("crud.$modelTable.sort_way") and session("crud.$modelTable.sort_col")) + ⌫ + @endif +
+ @foreach($model->{$fieldName} as $pSite) + {{ $pSite->{$prop['belongsToManyLabel']} }} + @endforeach + @include('crud-policies::crud.printfield', [ + 'action' => CrudAction::viewAny(), + 'field' => $model->{$fieldName}, + 'props' => $prop, + "$modelTable$fieldName" => ${"$modelTable$fieldName"} ?? null + ]){{ $model->getAccountsAttribute() }}{{ $model->getTotalOptinsAttribute() }}{{ $model->created_at->format('m/d/Y à H:i') }} +
+ @can('view', $model) + {{ __('crud-policies::crud.view') }} + @endcan + @can('update', $model) + {{ __('crud-policies::crud.edit') }} + @endcan + @can('delete', $model) +
+ @csrf + @method('DELETE') + +
+ @endcan + @can('viewAny', \App\Models\Log::class) + {{ __('Journaux') }} + @endcan + @can('viewAny', \App\Models\File::class) + {{ __('Fichiers') }} + @endcan +
+
+ {{ __('crud-policies::crud.nothingtoshow') }} +
+ {{ $models->links() }} +
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/brands/index.blade.php b/resources/views/brands/index.blade.php deleted file mode 100644 index 1c63dbd..0000000 --- a/resources/views/brands/index.blade.php +++ /dev/null @@ -1,28 +0,0 @@ -@extends('layout.app') - -@section('content') -
-

{{ __('Gestion des marques') }} {{ __('Liste') }}

- {{ __('Ajouter') }} -
- - - - - - - - - - @foreach ($brands as $brand) - - - - - - - - @endforeach - -
{{ __('Nom de la marque') }}{{ __('Nombre de comptes') }}{{ __('Nombre d\'optins') }}{{ __('Date d\'ajout en base') }}
{{ $brand->name }}{{ $brand->accounts }}{{ $brand->total_optins }}{{ Carbon::parse($brand->created_at)->format('d/m/Y à H:i') }}{{ __('Modifier') }}
-@endsection diff --git a/resources/views/brands/manage.blade.php b/resources/views/brands/manage.blade.php deleted file mode 100644 index 036e0f0..0000000 --- a/resources/views/brands/manage.blade.php +++ /dev/null @@ -1,30 +0,0 @@ -@extends('layout.app') - -@section('content') -
-

{{ __('Gestion des marques') }} {{ __('Gestion') }}

- @if ($errors->any()) -
    - @foreach(session('errors')->all(':message') as $error) -
  • {{ $error }}
  • - @endforeach -
- @endif - @if (session('success')) - {!! session('success') !!} - @endif - {{ __('Retour') }} -
-
-
- @csrf -
- - -
-
- -
-
-
-@endsection diff --git a/resources/views/customer/export.blade.php b/resources/views/customer/export.blade.php new file mode 100644 index 0000000..b7d8726 --- /dev/null +++ b/resources/views/customer/export.blade.php @@ -0,0 +1,68 @@ +@extends('layouts.app') + +@section('title', sprintf('%s - %s', __('Newsletter Contacts'), __('Export'))) +@section('description', sprintf('%s - %s', __('Newsletter Contacts'), __('Export'))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ +
+
+
+ @csrf +
+
+

{{ __('Exporter un liste de client pour une newsletter') }}

+
+
+
+
+
+ {{ __('La marque concernée') }} +
+ + +
+
+
+
+
+
+
+ {{ __('Type d\'export') }} + @foreach(CustomerExportType::toArray() as $i => $exportType) +
+ + +
+ @endforeach +
+
+
+
+
+ +
+
+
+
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/customer/index-tableHeaders.blade.php b/resources/views/customer/index-tableHeaders.blade.php new file mode 100644 index 0000000..cfee811 --- /dev/null +++ b/resources/views/customer/index-tableHeaders.blade.php @@ -0,0 +1,73 @@ + + @php $colname = 'customers.email' @endphp + {{ __('Email')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + + @php $colname = 'customer_infos.lastname' @endphp + {{ __('Nom')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + + @php $colname = 'customer_infos.firstname' @endphp + {{ __('Prénom')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + + @php $colname = 'customer_infos.opt_in' @endphp + {{ __('Opt-In')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + + @php $colname = 'brands.name' @endphp + {{ __('Marque')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + + @php $colname = 'customer_logins.status' @endphp + {{ __('Activé ?')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + + @php $colname = 'customer_logins.last_connection' @endphp + {{ __('Dernière connexion')}} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + + {{ __('Voir')}} + diff --git a/resources/views/customer/index.blade.php b/resources/views/customer/index.blade.php new file mode 100644 index 0000000..1cc32f9 --- /dev/null +++ b/resources/views/customer/index.blade.php @@ -0,0 +1,108 @@ +@extends('layouts.app') + +@section('title', sprintf('%s - %s', Str::ucfirst(Str::plural(trans('models.classes.customers'))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), Str::ucfirst(Str::plural(trans('models.classes.customers'))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ @include('crud-policies::crud.modules.breadcrumb', ['action' => CrudAction::viewAny()]) + @include('crud-policies::crud.modules.actionbar.bar', ['action' => CrudAction::viewAny()]) +
+
+
+
+
+
+ + + + + + + @if(request()->brand) + + @endif + {{ __('crud-policies::crud.reset') }} + +
+
+
+
+ {{ $customers->appends(Request::except('rst'))->links() }} + + + + @include('customer.index-tableHeaders') + + + + + @if(count($customers)) + + {{-- DISPLAY MODELS --}} + @foreach($customers as $customerInfo) + + + + + + + + + + + {{-- MODEL ACTIONS --}} + + + @endforeach + @else + + + + @endif + +
+ @if(session("crud.$modelTable.sort_way") and session("crud.$modelTable.sort_col")) + ⌫ + @endif +
+ {{ $customerInfo->customer->email }} + + {{ $customerInfo->firstname }} + + {{ $customerInfo->lastname }} + + {{ $customerInfo->opt_in ? 'Oui' :'Non' }} + + {{ $customerInfo->brand->name }} + + {{ $customerInfo->status ? 'Oui' :'Non' }} + + {{ $customerInfo->last_connection }} + + +
+ {{ __('crud-policies::crud.nothingtoshow') }} +
+ {{ $customers->appends(Request::except('rst'))->links() }} +
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/customer/show.blade.php b/resources/views/customer/show.blade.php new file mode 100644 index 0000000..0b12f77 --- /dev/null +++ b/resources/views/customer/show.blade.php @@ -0,0 +1,113 @@ +@extends('layouts.app') + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ +
+
+
+
+
+

{{ __('Informations du client') }} {{ $customerInfos->firstname }} {{ $customerInfos->lastname }} - {{ Str::singular(__('models.classes.brands')) }} {{ $customerInfos->brand->name }}

+ Retour +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @if($customerInfos->customer->optInHistory()->orderBy('created_at', 'DESC')->exists()) + + @else + + @endif + + + + + + + + + + + + + + + + + + + + + + +
{{ __('Email') }}{{ $customerInfos->customer->email }}
Prénom{{ $customerInfos->firstname }}
Nom{{ $customerInfos->lastname }}
Date de naissance{{ \Carbon\Carbon::parse($customerInfos->birth_date)->format('d/m/Y') }}
Téléphone{{ $customerInfos->phone }}
Adresse{{ $customerInfos->address }}
Adresse complémentaire{{ $customerInfos->address2 }}
Pays{{ $customerInfos->country }}
Ville{{ $customerInfos->city }}
Code postal{{ $customerInfos->postcode }}
Abonné à la newsletter{{ $customerInfos->opt_in === 1 ? "Oui" : "Non" }}
Date de la dernière modification de l'abonnement{{ \Carbon\Carbon::parse($customerInfos->customer->optInHistory()->orderBy('created_at', 'DESC')->first()->created_at)->format('d/m/Y à H:i') }}
Dernière connexion{{ \Carbon\Carbon::parse($customerLogin->last_connection)->format('d/m/Y à H:i') }}
Status du compte{{ $customerLogin->status === 1 ? "Activé" : "Non activé" }}
Hashcode{{ $customerInfos->hashcode }}
Date de création{{ \Carbon\Carbon::parse($customerInfos->created_at)->format('d/m/Y à H:i') }}
Date de modification{{ \Carbon\Carbon::parse($customerInfos->updated_at)->format('d/m/Y à H:i') }}
+
+ @csrf + @method('DELETE') + +
+
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/customers/index.blade.php b/resources/views/customers/index.blade.php deleted file mode 100644 index ba4ad56..0000000 --- a/resources/views/customers/index.blade.php +++ /dev/null @@ -1,23 +0,0 @@ -@extends('layout.app') - -@section('content') -@if (session()->has('success')) -
-
-

{{ session()->get('success') }}

-
-
-@endif -@if ($errors->any()) -
-
-
    - @foreach ($errors->all() as $error) -
  • {{ $error }}
  • - @endforeach -
-
-
-@endif - -@endsection diff --git a/resources/views/customers/show.blade.php b/resources/views/customers/show.blade.php deleted file mode 100644 index 2005343..0000000 --- a/resources/views/customers/show.blade.php +++ /dev/null @@ -1,98 +0,0 @@ -@extends('layout.app') - -@section('content') -
-

Informations du client {{ $customerInfos->firstname }} {{ $customerInfos->lastname }} - Marque {{ $customerInfos->brand->name }}

- Retour -
- @if ($errors->any()) -
-
    - @foreach ($errors->all() as $error) -
  • {{ $error }}
  • - @endforeach -
-
- @endif - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @if($customerInfos->customer->optInHistory()->orderBy('created_at', 'DESC')->exists()) - - @else - - @endif - - - - - - - - - - - - - - - - - - - - - - -
Email{{ $customerInfos->customer->email }}
Prénom{{ $customerInfos->firstname }}
Nom{{ $customerInfos->lastname }}
Date de naissance{{ \Carbon\Carbon::parse($customerInfos->birth_date)->format('d/m/Y') }}
Téléphone{{ $customerInfos->phone }}
Adresse{{ $customerInfos->address }}
Adresse complémentaire{{ $customerInfos->address2 }}
Pays{{ $customerInfos->country }}
Ville{{ $customerInfos->city }}
Code postal{{ $customerInfos->postcode }}
Abonné à la newsletter{{ $customerInfos->opt_in === 1 ? "Oui" : "Non" }}
Date de la dernière modification de l'abonnement{{ \Carbon\Carbon::parse($customerInfos->customer->optInHistory()->orderBy('created_at', 'DESC')->first()->created_at)->format('d/m/Y à H:i') }}
Dernière connexion{{ \Carbon\Carbon::parse($customerLogin->last_connection)->format('d/m/Y à H:i') }}
Status du compte{{ $customerLogin->status === 1 ? "Activé" : "Non activé" }}
Hashcode{{ $customerInfos->hashcode }}
Date de création{{ \Carbon\Carbon::parse($customerInfos->created_at)->format('d/m/Y à H:i') }}
Date de modification{{ \Carbon\Carbon::parse($customerInfos->updated_at)->format('d/m/Y à H:i') }}
-
- @csrf - @method('DELETE') - -
-@endsection diff --git a/resources/views/layout/app.blade.php b/resources/views/layout/app.blade.php deleted file mode 100644 index 84fe32e..0000000 --- a/resources/views/layout/app.blade.php +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - Tableau de bord - - - - - - -
- - -
-
- - -
- @yield('content') -
-
-
-
- - @yield('scripts') - - diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php new file mode 100644 index 0000000..c93ef72 --- /dev/null +++ b/resources/views/layouts/app.blade.php @@ -0,0 +1,35 @@ + + + + @include('layouts.backend.head') + @stack('styles') + @crudPoliciesCSS() + + +
+ @include('layouts.backend.navbar') +
+
+ @if(isset($modelsClasses)) + @include('layouts.backend.sidenav') +
+ @else +
+ @endif + @yield('content') +
+
+
+ @include('layouts.backend.footer') +
+
+
+ @stack('scriptsConstants') + @include('crud-policies::crud.modules.scriptConstants') + + + + @crudPoliciesJS() + @stack('scripts') + + diff --git a/resources/views/layouts/backend/footer.blade.php b/resources/views/layouts/backend/footer.blade.php new file mode 100644 index 0000000..9a24737 --- /dev/null +++ b/resources/views/layouts/backend/footer.blade.php @@ -0,0 +1,10 @@ +
+
+ {{ $license }} + - + {{ $name }} - {{ $version }} + - + LDC Web Services + © {{ date('Y') }} +
+
diff --git a/resources/views/layouts/backend/head.blade.php b/resources/views/layouts/backend/head.blade.php new file mode 100644 index 0000000..668513b --- /dev/null +++ b/resources/views/layouts/backend/head.blade.php @@ -0,0 +1,32 @@ + + + +{{ config('app.name') }}@hasSection('title') - @yield('title')@endif + + + +@hasSection('canonical') + +@else + +@endif + + +@hasSection('metaIndex') + +@else + +@endif + + +{{-- + + + --}} + +@preload('mix-manifest.json') + + + + + diff --git a/resources/views/layouts/backend/navbar.blade.php b/resources/views/layouts/backend/navbar.blade.php new file mode 100644 index 0000000..177643a --- /dev/null +++ b/resources/views/layouts/backend/navbar.blade.php @@ -0,0 +1,15 @@ + diff --git a/resources/views/layouts/backend/sidenav.blade.php b/resources/views/layouts/backend/sidenav.blade.php new file mode 100644 index 0000000..280b08a --- /dev/null +++ b/resources/views/layouts/backend/sidenav.blade.php @@ -0,0 +1,70 @@ + diff --git a/resources/views/login.blade.php b/resources/views/login.blade.php index 2b35965..1c3d682 100644 --- a/resources/views/login.blade.php +++ b/resources/views/login.blade.php @@ -1,78 +1,10 @@ - - - - - - Tableau de bord +@extends('layouts.app') - - - - - - +@section('content') + +@endsection diff --git a/resources/views/mail/service-renewed-plain.blade.php b/resources/views/mail/service-renewed-plain.blade.php new file mode 100644 index 0000000..b3b0c69 --- /dev/null +++ b/resources/views/mail/service-renewed-plain.blade.php @@ -0,0 +1,8 @@ + +{{ config('app.name') }} Service Warning + +Un service vient d'être régénéré sur {{ $appName }} +{{ $service->name }} (marque : {{ $service->brand->name }}) +Régénéré le {{ $service->updated_at->format('D/m/Y H:i') }} +par {{ $by }} +Celà va empêcher le service de fonctionner tant que les crédentials d'api n'auront pas été mis à jour sur le service concerné, veuillez faire au plus vite ! diff --git a/resources/views/mail/service-renewed.blade.php b/resources/views/mail/service-renewed.blade.php new file mode 100644 index 0000000..31a1180 --- /dev/null +++ b/resources/views/mail/service-renewed.blade.php @@ -0,0 +1,13 @@ + + + + {{ config('app.name') }} Service Warning + + + +

Un service vient d'être régénéré sur {{ $appName }}

+

{{ $service->name }} (marque : {{ $service->brand->name }})

+

Régénéré le {{ $service->updated_at->format('D d/m/Y H:i') }}
par {{ $by }}

+

Celà va empêcher le service de fonctionner tant que les crédentials d'api n'auront pas été mis à jour sur le service concerné, veuillez faire au plus vite !

+ + diff --git a/resources/views/modules/crudAction.blade.php b/resources/views/modules/crudAction.blade.php new file mode 100644 index 0000000..7536740 --- /dev/null +++ b/resources/views/modules/crudAction.blade.php @@ -0,0 +1,4 @@ +@if(request()->question) +{{ Str::ucfirst(__('models.common.question')) }} +{{ Str::ucfirst(__('models.classes.answers')) }} +@endif diff --git a/resources/views/modules/flashMessage.blade.php b/resources/views/modules/flashMessage.blade.php new file mode 100644 index 0000000..919668a --- /dev/null +++ b/resources/views/modules/flashMessage.blade.php @@ -0,0 +1,44 @@ +@if ($message = Session::get('success')) +
+ + {!! nl2br(e($message)) !!} +
+@endif + + +@if ($message = Session::get('error')) +
+ + {!! nl2br(e($message)) !!} +
+@endif + + +@if ($message = Session::get('warning')) +
+ + {!! nl2br(e($message)) !!} +
+@endif + + +@if ($message = Session::get('info')) +
+ + {!! nl2br(e($message)) !!} +
+@endif + + +@if ($errors->any()) +
+ + @if ($errors->any()) +
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+ @endif +
+@endif diff --git a/resources/views/question/export.blade.php b/resources/views/question/export.blade.php new file mode 100644 index 0000000..1f28055 --- /dev/null +++ b/resources/views/question/export.blade.php @@ -0,0 +1,53 @@ +@extends('layouts.app') + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('Export'))) +@section('description', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('Export'))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ +
+
+
+ @csrf +
+
+

{{ __('Exporter les réponses au questions') }}

+
+
+
+
+
+ {{ __('La marque concernée') }} +
+ + +
+
+
+
+
+
+ +
+
+
+
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/question/index.blade.php b/resources/views/question/index.blade.php new file mode 100644 index 0000000..80b294b --- /dev/null +++ b/resources/views/question/index.blade.php @@ -0,0 +1,125 @@ +@extends($viewLayout) + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ @include('crud-policies::crud.modules.breadcrumb', ['action' => CrudAction::viewAny()]) + @include('crud-policies::crud.modules.actionbar.bar', ['action' => CrudAction::viewAny()]) +
+
+
+
+
+
+ + + + + + + @if(request()->brand) + + @endif + {{ __('crud-policies::crud.reset') }} + +
+
+
+
+ {{ $models->appends(Request::except('rst'))->links() }} + + + @include('crud-policies::crud.modules.sorter') + + + @if(count($models)) + + {{-- INIT QUERIES for OPTIMIZING --}} + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if($prop['type']->equals(CrudType::order())) + @php ${"$modelTable$fieldName"} = $modelClass::max($fieldName); @endphp + @endif + @if($prop['type']->equals(CrudType::belongsTo())) + @php try { $models->load(Str::singular((new $prop['belongsTo']())->getTable())); } catch(\Exception $e) {} @endphp + @endif + @if($prop['type']->equals(CrudType::belongsToMany())) + @php $models->load("$fieldName"); @endphp + @endif + @endforeach + + {{-- DISPLAY MODELS --}} + @foreach($models as $model) + + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if(in_array(CrudAction::viewAny(), $prop['actions'])) + @switch($prop['type']) + @case(CrudType::belongsToMany() and $prop['belongsToMany'] === \App\Models\Project::class) + + @break + @case(CrudType::password()) + {{-- Ignore --}} + @break + @default + + @endswitch + @endif + @endforeach + + {{-- MODEL ACTIONS --}} + + + @endforeach + @else + + + + @endif + +
+ @foreach($model->{$fieldName} as $pSite) + {{ $pSite->{$prop['belongsToManyLabel']} }} + @endforeach + @include('crud-policies::crud.printfield', [ + 'action' => CrudAction::viewAny(), + 'field' => $model->{$fieldName}, + 'props' => $prop, + "$modelTable$fieldName" => ${"$modelTable$fieldName"} ?? null + ]) +
+ @can('view', $model) + {{ __('crud-policies::crud.view') }} + @endcan + @can('update', $model) + {{ __('crud-policies::crud.edit') }} + @endcan + @can('delete', $model) +
+ @csrf + @method('DELETE') + +
+ @endcan + @can('viewAny', \App\Models\Answer::class) + {{ Str::ucfirst(__('models.classes.answers')) }} + @endcan +
+
+ {{ __('crud-policies::crud.nothingtoshow') }} +
+ {{ $models->links() }} +
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/service/index.blade.php b/resources/views/service/index.blade.php new file mode 100644 index 0000000..f400938 --- /dev/null +++ b/resources/views/service/index.blade.php @@ -0,0 +1,158 @@ +@extends($viewLayout) + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ @include('crud-policies::crud.modules.breadcrumb', ['action' => CrudAction::viewAny()]) + @include('crud-policies::crud.modules.actionbar.bar', ['action' => CrudAction::viewAny()]) +
+
+
+
+
+
+ + + + @if(request()->brand) + + @endif + {{ __('crud-policies::crud.reset') }} + +
+
+
+
+ + + + @foreach ($modelClass::getEditableProperties() as $colname => $prop) + @if(in_array(CrudAction::viewAny(), $prop['actions'])) + @switch($prop['type']) + @case(CrudType::password()) + {{-- Ignore --}} + @break + @default + + @endswitch + @endif + @endforeach + + + + + + + + @if(count($models)) + + {{-- INIT QUERIES for OPTIMIZING --}} + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if($prop['type']->equals(CrudType::order())) + @php ${"$modelTable$fieldName"} = $modelClass::max($fieldName); @endphp + @endif + @if($prop['type']->equals(CrudType::belongsTo())) + @php try { $models->load(Str::singular((new $prop['belongsTo']())->getTable())); } catch(\Exception $e) {} @endphp + @endif + @if($prop['type']->equals(CrudType::belongsToMany())) + @php $models->load("$fieldName"); @endphp + @endif + @endforeach + + {{-- DISPLAY MODELS --}} + @foreach($models as $model) + + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if(in_array(CrudAction::viewAny(), $prop['actions'])) + @switch($prop['type']) + @case(CrudType::belongsToMany() and $prop['belongsToMany'] === \App\Models\Project::class) + + @break + @case(CrudType::password()) + {{-- Ignore --}} + @break + @default + + @endswitch + @endif + @endforeach + + {{-- INFO COLS --}} + + + + + {{-- MODEL ACTIONS --}} + + + @endforeach + @else + + + + @endif + +
+ {{ $prop['label'] }} + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'desc' and session("crud.$modelTable.sort_col") === $colname)) +  ↓  + @endif + @if(!session("crud.$modelTable.sort_way") or session("crud.$modelTable.sort_col") !== $colname or (session("crud.$modelTable.sort_way") === 'asc' and session("crud.$modelTable.sort_col") === $colname)) +  ↑  + @endif + + {{ __('Date du Bearer token')}} + + {{ __('Régénerer un token')}} + + {{ __('Date de création')}} + + @if(session("crud.$modelTable.sort_way") and session("crud.$modelTable.sort_col")) + ⌫ + @endif +
+ @foreach($model->{$fieldName} as $pSite) + {{ $pSite->{$prop['belongsToManyLabel']} }} + @endforeach + @include('crud-policies::crud.printfield', [ + 'action' => CrudAction::viewAny(), + 'field' => $model->{$fieldName}, + 'props' => $prop, + "$modelTable$fieldName" => ${"$modelTable$fieldName"} ?? null + ]){{ Carbon::parse($model->bearer_token_date)->format('m/d/Y à H:i') }}
@csrf
{{ $model->created_at->format('m/d/Y à H:i') }} +
+ @can('view', $model) + {{ __('crud-policies::crud.view') }} + @endcan + @can('update', $model) + {{ __('crud-policies::crud.edit') }} + @endcan + @can('delete', $model) +
+ @csrf + @method('DELETE') + +
+ @endcan + @can('viewAny', \App\Models\Log::class) + {{ __('Journaux') }} + @endcan + @can('viewAny', \App\Models\File::class) + {{ __('Fichiers') }} + @endcan +
+
+ {{ __('crud-policies::crud.nothingtoshow') }} +
+ {{ $models->links() }} +
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/services/index.blade.php b/resources/views/services/index.blade.php deleted file mode 100644 index 372f0de..0000000 --- a/resources/views/services/index.blade.php +++ /dev/null @@ -1,36 +0,0 @@ -@extends('layout.app') - -@section('content') -
-

{{ __('Gestion des services') }} {{ __('Liste') }}

- @if (session('success')) - {!! session('success') !!} - @endif - @if (session('error')) - {!! session('error') !!} - @endif - {{ __('Ajouter') }} -
- - - - - - - - - - - @foreach ($services as $service) - - - - - - - - - @endforeach - -
{{ __('Nom') }}{{ __('Marque') }}{{ __('Date du token') }}{{ __('Regénérer un token') }}{{ __('Date de création') }}
{{ $service->name }}{{ $service->brand->name }}{{ Carbon::parse($service->bearer_token_date)->format('d/m/Y à H:i') }}{{ __('Générer') }}{{ Carbon::parse($service->created_at)->format('d/m/Y à H:i') }}{{ __('Modifier') }}
-@endsection diff --git a/resources/views/services/manage.blade.php b/resources/views/services/manage.blade.php deleted file mode 100644 index f888168..0000000 --- a/resources/views/services/manage.blade.php +++ /dev/null @@ -1,42 +0,0 @@ -@extends('layout.app') - -@section('content') -
-

{{ __('Gestion des services') }} {{ __('Gestion') }}

- @if ($errors->any()) -
    - @foreach(session('errors')->all(':message') as $error) -
  • {{ $error }}
  • - @endforeach -
- @endif - @if (session('success')) - {!! session('success') !!} - @endif - {{ __('Retour') }} -
-
-
- @csrf -
- - -
- @if (!$edit) -
- - -
- @else - - @endif -
- -
-
-
-@endsection diff --git a/resources/views/single-optins/index.blade.php b/resources/views/single-optins/index.blade.php deleted file mode 100644 index df1e97a..0000000 --- a/resources/views/single-optins/index.blade.php +++ /dev/null @@ -1,5 +0,0 @@ -@extends('layout.app') - -@section('content') - -@endsection diff --git a/resources/views/single_optin/index.blade.php b/resources/views/single_optin/index.blade.php new file mode 100644 index 0000000..2d0c900 --- /dev/null +++ b/resources/views/single_optin/index.blade.php @@ -0,0 +1,121 @@ +@extends($viewLayout) + +@section('title', sprintf('%s - %s', transFb(sprintf('models.classes.%s', strtolower(Str::plural(class_basename($modelClass)))), Str::plural(class_basename($modelClass))), __('crud-policies::crud.viewAny'))) +@section('description', sprintf('%s %s', __('crud-policies::crud.viewAny'), trans(Str::plural(class_basename($modelClass))))) +@section('metaIndex', 'noindex,nofollow') + +@section('content') +
+ @include('crud-policies::crud.modules.flashMessage') +
+ @include('crud-policies::crud.modules.breadcrumb', ['action' => CrudAction::viewAny()]) + @include('crud-policies::crud.modules.actionbar.bar', ['action' => CrudAction::viewAny()]) +
+
+
+
+
+
+ + + + + + + @if(request()->brand) + + @endif + {{ __('crud-policies::crud.reset') }} + +
+
+
+
+ + + @include('crud-policies::crud.modules.sorter') + + + @if(count($models)) + + {{-- INIT QUERIES for OPTIMIZING --}} + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if($prop['type']->equals(CrudType::order())) + @php ${"$modelTable$fieldName"} = $modelClass::max($fieldName); @endphp + @endif + @if($prop['type']->equals(CrudType::belongsTo())) + @php try { $models->load(Str::singular((new $prop['belongsTo']())->getTable())); } catch(\Exception $e) {} @endphp + @endif + @if($prop['type']->equals(CrudType::belongsToMany())) + @php $models->load("$fieldName"); @endphp + @endif + @endforeach + + {{-- DISPLAY MODELS --}} + @foreach($models as $model) + + @foreach ($modelClass::getEditableProperties() as $fieldName => $prop) + @if(in_array(CrudAction::viewAny(), $prop['actions'])) + @switch($prop['type']) + @case(CrudType::belongsToMany() and $prop['belongsToMany'] === \App\Models\Project::class) + + @break + @case(CrudType::password()) + {{-- Ignore --}} + @break + @default + + @endswitch + @endif + @endforeach + + {{-- MODEL ACTIONS --}} + + + @endforeach + @else + + + + @endif + +
+ @foreach($model->{$fieldName} as $pSite) + {{ $pSite->{$prop['belongsToManyLabel']} }} + @endforeach + @include('crud-policies::crud.printfield', [ + 'action' => CrudAction::viewAny(), + 'field' => $model->{$fieldName}, + 'props' => $prop, + "$modelTable$fieldName" => ${"$modelTable$fieldName"} ?? null + ]) +
+ @can('view', $model) + {{ __('crud-policies::crud.view') }} + @endcan + @can('update', $model) + {{ __('crud-policies::crud.edit') }} + @endcan + @can('delete', $model) +
+ @csrf + @method('DELETE') + +
+ @endcan +
+
+ {{ __('crud-policies::crud.nothingtoshow') }} +
+ {{ $models->links() }} +
+
+@include('crud-policies::crud.modules.scriptConstants') +@endsection diff --git a/resources/views/vendor/crud-policies/crud/modules/actionbar/bar.blade.php b/resources/views/vendor/crud-policies/crud/modules/actionbar/bar.blade.php new file mode 100644 index 0000000..131ec85 --- /dev/null +++ b/resources/views/vendor/crud-policies/crud/modules/actionbar/bar.blade.php @@ -0,0 +1,21 @@ +
+ @switch($action) + @case(CrudAction::viewAny()) + @include('modules.crudAction') + @include('crud-policies::crud.modules.actionbar.create') + @break + @case(CrudAction::view()) + @include('modules.crudAction') + @include('crud-policies::crud.modules.actionbar.update') + @include('crud-policies::crud.modules.actionbar.delete') + @break + @case(CrudAction::create()) + @include('modules.crudAction') + @break + @case(CrudAction::update()) + @include('modules.crudAction') + @include('crud-policies::crud.modules.actionbar.view') + @include('crud-policies::crud.modules.actionbar.delete') + @break + @endswitch +
diff --git a/resources/views/vendor/crud-policies/crud/modules/actionbar/create.blade.php b/resources/views/vendor/crud-policies/crud/modules/actionbar/create.blade.php new file mode 100644 index 0000000..3cc5251 --- /dev/null +++ b/resources/views/vendor/crud-policies/crud/modules/actionbar/create.blade.php @@ -0,0 +1,3 @@ +@can('create', $modelClass) +{{ __('crud-policies::crud.create') }} +@endcan diff --git a/resources/views/vendor/crud-policies/crud/modules/actionbar/delete.blade.php b/resources/views/vendor/crud-policies/crud/modules/actionbar/delete.blade.php new file mode 100644 index 0000000..dc1fdcc --- /dev/null +++ b/resources/views/vendor/crud-policies/crud/modules/actionbar/delete.blade.php @@ -0,0 +1,7 @@ +@can('delete', $model) +
+ @csrf + @method('DELETE') + +
+@endcan diff --git a/resources/views/vendor/crud-policies/crud/modules/actionbar/update.blade.php b/resources/views/vendor/crud-policies/crud/modules/actionbar/update.blade.php new file mode 100644 index 0000000..9e2008f --- /dev/null +++ b/resources/views/vendor/crud-policies/crud/modules/actionbar/update.blade.php @@ -0,0 +1,3 @@ +@can('update', $model) +{{ __('crud-policies::crud.update') }} +@endcan diff --git a/resources/views/vendor/crud-policies/crud/modules/actionbar/view.blade.php b/resources/views/vendor/crud-policies/crud/modules/actionbar/view.blade.php new file mode 100644 index 0000000..2419cd7 --- /dev/null +++ b/resources/views/vendor/crud-policies/crud/modules/actionbar/view.blade.php @@ -0,0 +1,3 @@ +@can('view', $model) +{{ __('crud-policies::crud.view') }} +@endcan diff --git a/routes/web.php b/routes/web.php index 55b9237..cf418a2 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,10 +1,12 @@ name('login'); Route::post('/login', [LoginController::class, 'authenticate'])->name('authenticate'); Route::middleware(['auth'])->group(function () { Route::get('/', function () { - return redirect()->route('customers'); - }); - Route::get('/logout', [LoginController::class, 'logout'])->name('logout'); + return redirect()->route('brands.index'); + })->name('home'); + Route::post('/logout', [LoginController::class, 'logout'])->name('logout'); // Marques - Route::get('/brands', [BrandController::class, 'index'])->name('brands'); - Route::match(['get', 'post'], '/brand/manage/{brand?}', [BrandController::class, 'manage'])->name('manage-brand'); + Route::resource('brands', BrandController::class)->except([ + 'delete' + ]); + Route::match(['get', 'post'], '/brand/manage/{brand?}', [BrandController::class, 'manage']) + ->name('manage-brand'); // Services - Route::get('/services', [ServiceController::class, 'index'])->name('services'); - Route::match(['get', 'post'], '/service/manage/{service?}', [ServiceController::class, 'manage']) - ->name('manage-service'); - Route::get('/services/{service}/token/generate', [ServiceController::class, 'generateApiToken']) + Route::resource('services', ServiceController::class)->except([ + 'delete' + ]); + Route::post('/services/{service}/token/generate', [ServiceController::class, 'generateApiToken']) ->name('generate-token-service'); // Clients - Route::get('/customers', [CustomerController::class, 'index'])->name('customers'); - Route::get('/customers/filter/{texte}/{brand?}', [CustomerController::class, 'filter'])->name('filter-customer'); - Route::get('/customer/{customer}/{brand}', [CustomerController::class, 'show'])->name('show-customer'); - Route::delete('/customer/{customer}/{brand}', [CustomerController::class, 'delete'])->name('customers.delete'); + Route::get('/customers', [CustomerController::class, 'index'])->name('customers.index'); + Route::get('/customers/{customer}/{brand}', [CustomerController::class, 'show'])->name('customers.show'); + Route::delete('/customers/{customer}/{brand}', [CustomerController::class, 'delete'])->name('customers.delete'); + Route::get('/customers/export', [CustomerController::class, 'export'])->name('customers.export'); + Route::post('/customers/export', [CustomerController::class, 'exportSubmit'])->name('customers.exportSubmit'); // Single optins - Route::get('/single-optins', [SingleOptinsController::class, 'index'])->name('single-optins'); - Route::get('/single-optins/filter/{texte}/{brandId?}', [SingleOptinsController::class, 'filter']) - ->name('filter-single-optins'); - Route::post('/single-optins/{id}/delete', [SingleOptinsController::class, 'delete'])->name('single-optins-delete'); + Route::resource('single_optins', SingleOptinController::class); + Route::post('/single_optins/{id}/delete', [SingleOptinController::class, 'delete'])->name('single-optins-delete'); + + // Questions + Route::get('/questions/export', [QuestionController::class, 'export'])->name('questions.export'); + Route::post('/questions/export', [QuestionController::class, 'exportSubmit'])->name('questions.exportSubmit'); + Route::resource('questions', QuestionController::class); + Route::resource('questions.answers', AnswerController::class); }); diff --git a/tests/Unit/CrmClientV2RouterTest.php b/tests/Unit/CrmClientV2RouterTest.php index c4e9321..a2a87f6 100644 --- a/tests/Unit/CrmClientV2RouterTest.php +++ b/tests/Unit/CrmClientV2RouterTest.php @@ -20,7 +20,7 @@ class CrmClientV2RouterTest extends CrmClientTester $this->assertEquals($route->methods(), $routes[$route->getName()]['methods']); $this->assertEquals($route->uri(), $routes[$route->getName()]['uri']); } else { - $this->assertArrayNotHasKey($route->getName(), $routes); + $this->assertArrayNotHasKey($route->getName() ?? '', $routes); } } } diff --git a/webpack.mix.js b/webpack.mix.js index 434769a..ae418f1 100644 --- a/webpack.mix.js +++ b/webpack.mix.js @@ -1,15 +1,49 @@ +const path = require('path'); const mix = require('laravel-mix'); +const { CleanWebpackPlugin } = require('clean-webpack-plugin'); +require('laravel-mix-polyfill'); -/* - |-------------------------------------------------------------------------- - | Mix Asset Management - |-------------------------------------------------------------------------- - | - | Mix provides a clean, fluent API for defining some Webpack build steps - | for your Laravel applications. By default, we are compiling the CSS - | file for the application as well as bundling up all the JS files. - | - */ +mix.webpackConfig({ + resolve: { + alias: { + '@': path.resolve('resources/assets') + } + }, + plugins: [ + new CleanWebpackPlugin({ + cleanOnceBeforeBuildPatterns: [ + 'css/*', + 'js/*', + 'images/*', + 'fonts/*', + 'assets/*' + ] + }) + ], +}); -mix.js('resources/js/app.js', 'public/js') - .sass('resources/sass/app.scss', 'public/css'); +let assetDir = 'assets'; +mix.options({ + fileLoaderDirs: { + images: `${assetDir}/images`, + fonts: `${assetDir}/fonts` + }, + postCss: [ + require('postcss-discard-comments')({ + removeAll: true + }) + ] +}); + +// mix Backend +mix.js("resources/js/back.js", "public/js/preload-back.js") + .sass("resources/sass/back.scss", "public/css/preload-back.css") + // .vue() + .polyfill({ + enabled: true, + useBuiltIns: "usage", + targets: { "firefox": "50", "ie": 11 } + }); + +// Copy Blade Images Assets +mix.copyDirectory('resources/assets', 'public/assets');