Redo contact Part with dynamic data and remove Export + update API call for contacts
This commit is contained in:
parent
15ee6ece22
commit
fc17fa6cc1
46 changed files with 1915 additions and 242 deletions
46
app/Casts/AsArrayOfInput.php
Normal file
46
app/Casts/AsArrayOfInput.php
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace App\Casts;
|
||||
|
||||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
||||
|
||||
class AsArrayOfInput implements CastsAttributes
|
||||
{
|
||||
/**
|
||||
* Cast the given value.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param array $attributes
|
||||
* @return array<\App\Lib\Inputs\Definition\Input>
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
*/
|
||||
public function get($model, string $key, $value, array $attributes): array
|
||||
{
|
||||
// phpcs:enable
|
||||
return \collect(\json_decode($value, true))->map(function ($input) use ($model, $key, $attributes) {
|
||||
$inputCast = new AsInput();
|
||||
return $inputCast->get($model, $key, \json_encode($input), $attributes);
|
||||
})->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the given value for storage.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $key
|
||||
* @param \App\Lib\Inputs\Definition\Input $value
|
||||
* @param array $attributes
|
||||
* @return string Json encoded array<\App\Lib\Inputs\Definition\Input>
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
*/
|
||||
public function set($model, string $key, $value, array $attributes)
|
||||
{
|
||||
// phpcs:enable
|
||||
return \json_encode(\collect($value)->map(function ($input) use ($model, $key, $attributes) {
|
||||
$inputCast = new AsInput();
|
||||
return \json_decode($inputCast->set($model, $key, $input, $attributes));
|
||||
})->all());
|
||||
}
|
||||
}
|
||||
69
app/Casts/AsInput.php
Normal file
69
app/Casts/AsInput.php
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace App\Casts;
|
||||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\Input;
|
||||
use App\Lib\Inputs\Definition\InputData;
|
||||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
||||
|
||||
class AsInput implements CastsAttributes
|
||||
{
|
||||
/**
|
||||
* Cast the given value.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param array $attributes
|
||||
* @return \App\Lib\Inputs\Definition\Input
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceBeforeLastUsed
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed
|
||||
*/
|
||||
public function get($model, string $key, $value, array $attributes): Input
|
||||
{
|
||||
// phpcs:enable
|
||||
/** @var string $class */
|
||||
/** @var array<integer|string|boolean> $data */
|
||||
$inputData = \json_decode($value, true);
|
||||
$inputClass = InputTypeEnum::make($inputData['type'])->inputClass;
|
||||
return $inputClass::from(InputData::make(...\array_values($inputData)), $inputData['required'] ?? false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the given value for storage.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param string $key
|
||||
* @param \App\Lib\Inputs\Definition\Input $value
|
||||
* @param array $attributes
|
||||
* @return string Json encoded \App\Lib\Inputs\Definition\Input
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.TypeHintMissing
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceBeforeLastUsed
|
||||
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed
|
||||
*/
|
||||
public function set($model, string $key, $value, array $attributes)
|
||||
{
|
||||
// phpcs:enable
|
||||
$this->assertIsInput($value);
|
||||
/** @var \App\Lib\Inputs\Definition\Input $value */
|
||||
return $value->toJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert is instance of \App\Lib\Inputs\Definition\Input
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
* @throws \RuntimeException If the value is not an input.
|
||||
*/
|
||||
private function assertIsInput($value): void
|
||||
{
|
||||
if (!\is_object($value) or !\in_array(Input::class, \class_parents($value))) {
|
||||
$value = \json_encode($value);
|
||||
throw new \RuntimeException(
|
||||
__CLASS__ . ' needs value to be array of \'' . Input::class . "' given is {$value}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,17 +2,28 @@
|
|||
|
||||
namespace App\Enums\Formularies;
|
||||
|
||||
use App\Lib\Inputs\InputCheckbox;
|
||||
use App\Lib\Inputs\InputEmail;
|
||||
use App\Lib\Inputs\InputPhone;
|
||||
use App\Lib\Inputs\InputRadio;
|
||||
use App\Lib\Inputs\InputSelect;
|
||||
use App\Lib\Inputs\InputSelectMultiple;
|
||||
use App\Lib\Inputs\InputText;
|
||||
use Kwaadpepper\Enum\BaseEnumRoutable;
|
||||
|
||||
/**
|
||||
* This defines a data type.
|
||||
*
|
||||
* @property-read integer value
|
||||
* @property-read string label
|
||||
* @property-read string inputClass InputType class.
|
||||
*
|
||||
* @method static self text() input text
|
||||
* @method static self email() input email
|
||||
* @method static self phone() input phone
|
||||
* @method static self radio() input radio
|
||||
* @method static self select() input select
|
||||
* @method static self multipleselect() input multipleselect
|
||||
* @method static self selectMultiple() input selectMultiple
|
||||
* @method static self checkbox() input checkbox
|
||||
*/
|
||||
final class InputTypeEnum extends BaseEnumRoutable
|
||||
|
|
@ -29,7 +40,7 @@ final class InputTypeEnum extends BaseEnumRoutable
|
|||
'phone' => 3,
|
||||
'radio' => 4,
|
||||
'select' => 5,
|
||||
'multipleselect' => 6,
|
||||
'selectMultiple' => 6,
|
||||
'checkbox' => 7,
|
||||
];
|
||||
}
|
||||
|
|
@ -46,8 +57,39 @@ final class InputTypeEnum extends BaseEnumRoutable
|
|||
'phone' => __('téléphone'),
|
||||
'radio' => __('radio'),
|
||||
'select' => __('liste déroulante'),
|
||||
'multipleselect' => __('liste déroulante à choix multiple'),
|
||||
'selectMultiple' => __('liste déroulante à choix multiple'),
|
||||
'checkbox' => __('case à cocher'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum input Types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected static function inputTypes(): array
|
||||
{
|
||||
return [
|
||||
'text' => InputText::class,
|
||||
'email' => InputEmail::class,
|
||||
'phone' => InputPhone::class,
|
||||
'radio' => InputRadio::class,
|
||||
'select' => InputSelect::class,
|
||||
'selectMultiple' => InputSelectMultiple::class,
|
||||
'checkbox' => InputCheckbox::class,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @return integer|string
|
||||
* @throws \Kwaadpepper\Enum\Exceptions\UnknownEnumProperty If the prop cannot be found.
|
||||
*/
|
||||
public function __get(string $attribute)
|
||||
{
|
||||
if ($attribute === 'inputClass') {
|
||||
return $this->inputTypes()[$this->getDefinition()];
|
||||
}
|
||||
return parent::__get($attribute);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
namespace App\Http\Controllers\API;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\Contacts\DestroyContactsRequest;
|
||||
use App\Http\Requests\Api\Contacts\UpsertContactsRequest;
|
||||
use App\Http\Resources\AppUserResource;
|
||||
use App\Http\Resources\ContactResource;
|
||||
use App\Http\Resources\DirectoryResource;
|
||||
|
|
@ -18,7 +20,9 @@ use App\Models\Formulary;
|
|||
use App\Models\Setting;
|
||||
use Google\Cloud\Vision\V1\ImageAnnotatorClient;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
|
@ -35,17 +39,67 @@ class SyncController extends Controller
|
|||
return AppUserResource::collection(AppUser::where('status', 1)->get());
|
||||
}
|
||||
|
||||
// *** --- START CONTACTS ---
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \App\Http\Resources\ContactsCollection
|
||||
* Get Contacts
|
||||
*
|
||||
* @param \App\Models\AppUser $app_user
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function getContacts(Request $request)
|
||||
public function getContacts(AppUser $app_user)
|
||||
{
|
||||
$userId = $request->userId;
|
||||
$this->syncContacts($request->contacts, $userId);
|
||||
return ContactResource::collection(Contact::where('app_user_id', $userId)->get());
|
||||
return ContactResource::collection(
|
||||
Contact::query()->whereHas('appUser', function (Builder $q) use ($app_user) {
|
||||
$q->where('id', $app_user->id);
|
||||
})->get()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upsert contacts
|
||||
*
|
||||
* @param \App\Http\Requests\Api\Contacts\UpsertContactsRequest $request
|
||||
* @param \App\Models\AppUser $app_user
|
||||
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
||||
*/
|
||||
public function upsertContact(UpsertContactsRequest $request, AppUser $app_user)
|
||||
{
|
||||
$contactQuery = Contact::query()->whereHas('appUser', function (Builder $q) use ($app_user) {
|
||||
$q->where('id', $app_user->id);
|
||||
});
|
||||
|
||||
\collect($request->contacts)->each(function (array $contact) use ($contactQuery) {
|
||||
Arr::set($contact, 'data', Arr::get($contact, 'dataParsed'));
|
||||
/** @var \App\Models\Contact */
|
||||
$model = $contactQuery->where('id', Arr::get($contact, 'id'))->firstOrNew();
|
||||
$model->fill($contact);
|
||||
$model->saveOrFail();
|
||||
});
|
||||
|
||||
// * HTTP 200 is ok.
|
||||
return \response()->json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy contacts
|
||||
*
|
||||
* @param \App\Http\Requests\Api\Contacts\DestroyContactsRequest $request
|
||||
* @param \App\Models\AppUser $app_user
|
||||
* @return \Illuminate\Http\Resources\Json
|
||||
*/
|
||||
public function destroyContacts(DestroyContactsRequest $request, AppUser $app_user)
|
||||
{
|
||||
Contact::query()->whereIn('id', $request->contacts)->whereHas('appUser', function (Builder $q) use ($app_user) {
|
||||
$q->where('id', $app_user->id);
|
||||
})->delete();
|
||||
|
||||
// * HTTP 200 is ok.
|
||||
return \response()->json();
|
||||
}
|
||||
|
||||
// *** --- END CONTACTS ---
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \App\Http\Resources\DirectoriesCollection
|
||||
|
|
@ -162,76 +216,6 @@ class SyncController extends Controller
|
|||
return 'OK';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $contacts
|
||||
* @param mixed $userId
|
||||
* @return void
|
||||
*/
|
||||
private function syncContacts($contacts, $userId)
|
||||
{
|
||||
$contacts = json_decode(json_encode($contacts), false);
|
||||
foreach ($contacts as $contact) {
|
||||
if ($contact->to_delete === true) {
|
||||
$tmp = Contact::where([
|
||||
['id', '=', $contact->uniq_id],
|
||||
['app_user_id', '=', $contact->app_user_id]
|
||||
])->first();
|
||||
if ($tmp) {
|
||||
$tmp->delete();
|
||||
}
|
||||
} else {
|
||||
if ($contact->app_user_id != $userId) {
|
||||
$tmp = Contact::where([
|
||||
['id', '=', $contact->uniq_id],
|
||||
['app_user_id', '=', $userId]
|
||||
])->first();
|
||||
if ($tmp) {
|
||||
$tmp->delete();
|
||||
}
|
||||
}
|
||||
$tmp = Contact::where([
|
||||
['id', '=', $contact->uniq_id],
|
||||
['app_user_id', '=', $contact->app_user_id]
|
||||
])->first();
|
||||
if ($tmp) {
|
||||
$tmp->email = $contact->email;
|
||||
$tmp->type = $contact->type;
|
||||
$tmp->other = $contact->other;
|
||||
$tmp->select1 = $contact->select1;
|
||||
$tmp->select2 = $contact->select2;
|
||||
$tmp->lastname = $contact->lastname;
|
||||
$tmp->firstname = $contact->firstname;
|
||||
$tmp->company = $contact->company;
|
||||
$tmp->address = $contact->address;
|
||||
$tmp->phone = empty($contact->phone) ? "" : $contact->phone;
|
||||
$tmp->products = $contact->products;
|
||||
$tmp->notes = $contact->notes;
|
||||
$tmp->visits = $contact->visits;
|
||||
$tmp->app_user_id = $contact->app_user_id;
|
||||
$tmp->save();
|
||||
} else {
|
||||
$tmp = new Contact();
|
||||
$tmp->id = $contact->uniq_id;
|
||||
$tmp->email = $contact->email;
|
||||
$tmp->type = $contact->type;
|
||||
$tmp->other = $contact->other;
|
||||
$tmp->select1 = $contact->select1;
|
||||
$tmp->select2 = $contact->select2;
|
||||
$tmp->lastname = $contact->lastname;
|
||||
$tmp->firstname = $contact->firstname;
|
||||
$tmp->company = $contact->company;
|
||||
$tmp->address = $contact->address;
|
||||
$tmp->phone = empty($contact->phone) ? "" : $contact->phone;
|
||||
$tmp->products = json_encode($contact->products);
|
||||
$tmp->notes = $contact->notes;
|
||||
$tmp->visits = $contact->visits;
|
||||
$tmp->app_user_id = $contact->app_user_id;
|
||||
$tmp->save();
|
||||
} //end if
|
||||
} //end if
|
||||
} //end foreach
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return void
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ class AppUserController extends Controller
|
|||
|
||||
/** @var integer $pagination Items per page */
|
||||
if ($request->pagination) {
|
||||
// FIXME: Add pagination validation.
|
||||
Cache::forever('pagination', intval($request->pagination));
|
||||
}
|
||||
$app_users = $app_users->paginate(intval(Cache::get('pagination')) ?? config('pagination.default'));
|
||||
|
|
@ -64,7 +65,7 @@ class AppUserController extends Controller
|
|||
public function create()
|
||||
{
|
||||
$directories = Directory::renderDirectories(Directory::where('needAuthorization', 1)
|
||||
->orderBy('name', 'ASC')->get());
|
||||
->orderBy('name', 'ASC')->get());
|
||||
|
||||
return view('bo.pages.app-users.create', compact('directories'));
|
||||
}
|
||||
|
|
@ -109,7 +110,7 @@ class AppUserController extends Controller
|
|||
public function edit(AppUser $app_user)
|
||||
{
|
||||
$directories = Directory::renderDirectories(Directory::where('needAuthorization', 1)
|
||||
->orderBy('name', 'ASC')->get());
|
||||
->orderBy('name', 'ASC')->get());
|
||||
$app_user->directories = Directory::renderDirectories($app_user->directories);
|
||||
|
||||
return view('bo.pages.app-users.edit', [
|
||||
|
|
|
|||
60
app/Http/Controllers/Bo/ContactController.php
Normal file
60
app/Http/Controllers/Bo/ContactController.php
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bo;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Contact;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ContactController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Builder $contacts */
|
||||
$contacts = Contact::query();
|
||||
|
||||
/** @var string $search Search field */
|
||||
if ($request->search) {
|
||||
$this->searchQuery(
|
||||
$contacts,
|
||||
$request->search,
|
||||
null,
|
||||
'firstname',
|
||||
'lastname',
|
||||
'email',
|
||||
);
|
||||
}
|
||||
$searchFields = \implode(',', [trans('Nom'), trans('Prénom'), trans('Email')]);
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($contacts);
|
||||
|
||||
/** @var integer $pagination Items per page */
|
||||
if ($request->pagination) {
|
||||
// FIXME: Add pagination validation.
|
||||
Cache::forever('pagination', intval($request->pagination));
|
||||
}
|
||||
$contactModelList = $contacts->paginate(intval(Cache::get('pagination')) ?? config('pagination.default'));
|
||||
|
||||
return view('bo.pages.contacts.index', compact('contactModelList', 'searchFields'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \App\Models\Contact $contact
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Contact $contact)
|
||||
{
|
||||
return \view('bo.pages.contacts.show', ['contactModel' => $contact]);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,48 +19,4 @@ class DashboardController extends Controller
|
|||
{
|
||||
return view('bo.pages.dashboard');
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupérer les contacts (fichier .csv) et les fichiers.
|
||||
*
|
||||
* @return \Illuminate\Http\Response|\Illuminate\Contracts\Routing\ResponseFactory
|
||||
*/
|
||||
public function exportContact()
|
||||
{
|
||||
$csv_file = 'export-contacts.csv';
|
||||
$csvExporter = new \Laracsv\Export();
|
||||
$contacts = Contact::all();
|
||||
|
||||
$csvExporter->beforeEach(function ($contact) {
|
||||
$contact->app_user_id = $contact->firstname . " " . $contact->lastname;
|
||||
$contact->phone = "$contact->phone";
|
||||
});
|
||||
|
||||
$csvExporter->getWriter()->setDelimiter(';');
|
||||
$csvExporter->getWriter()->setEnclosure('"');
|
||||
$csvExporter->getWriter()->setOutputBOM(\League\Csv\Reader::BOM_UTF8);
|
||||
$csvExporter->build($contacts, [
|
||||
'app_user_id' => 'Propriétaire',
|
||||
'email' => 'Email',
|
||||
'type' => 'Type du contact',
|
||||
'other' => 'Type autre',
|
||||
'select1' => 'Select n°1',
|
||||
'select2' => 'Select n°2',
|
||||
'name' => 'Nom',
|
||||
'firstname' => 'Prénom',
|
||||
'company' => 'Entreprise',
|
||||
'address' => 'Adresse',
|
||||
'phone' => 'Téléphone',
|
||||
'notes' => 'Notes',
|
||||
'visits' => 'Visites',
|
||||
]);
|
||||
|
||||
Storage::disk('public')->put($csv_file, $csvExporter->getWriter()->getContent());
|
||||
|
||||
return response()->download(
|
||||
storage_path('app/public/') . "$csv_file",
|
||||
'contacts.csv',
|
||||
['Content-Type' => 'text/csv; charset=utf-8']
|
||||
)->deleteFileAfterSend();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ class DocumentController extends Controller
|
|||
|
||||
/** @var integer $pagination Items per page */
|
||||
if ($request->pagination) {
|
||||
// FIXME: Add pagination validation.
|
||||
Cache::forever('pagination', intval($request->pagination));
|
||||
}
|
||||
$documents = $documents->paginate(intval(Cache::get('pagination')) ?? config('pagination.default'));
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class FormularyController extends Controller
|
|||
|
||||
/** @var integer $pagination Items per page */
|
||||
if ($request->pagination) {
|
||||
// FIXME: Add pagination validation.
|
||||
Cache::forever('pagination', intval($request->pagination));
|
||||
}
|
||||
$formulariesModel = $formularies->paginate(intval(Cache::get('pagination')) ?? config('pagination.default'));
|
||||
|
|
@ -100,10 +101,10 @@ class FormularyController extends Controller
|
|||
{
|
||||
if ($formulary->status->value === InputStatusEnum::system()->value) {
|
||||
return redirect()->route('bo.formularies.index')
|
||||
->with('error', trans(
|
||||
'Administration du champs :name impossible car il est vérouillé !',
|
||||
['name' => $formulary->name]
|
||||
));
|
||||
->with('error', trans(
|
||||
'Administration du champs :name impossible car il est vérouillé !',
|
||||
['name' => $formulary->name]
|
||||
));
|
||||
} else {
|
||||
return view('bo.pages.formularies.edit', [
|
||||
'formularyModel' => $formulary
|
||||
|
|
|
|||
44
app/Http/Requests/Api/Contacts/DestroyContactsRequest.php
Normal file
44
app/Http/Requests/Api/Contacts/DestroyContactsRequest.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Api\Contacts;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class DestroyContactsRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
// * Check is done with api.token middleware
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->merge([
|
||||
'contacts' => \collect($this->ids)->filter()->all()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'contacts' => 'required|array',
|
||||
'contacts.*' => 'required|uuid',
|
||||
];
|
||||
}
|
||||
}
|
||||
132
app/Http/Requests/Api/Contacts/UpsertContactsRequest.php
Normal file
132
app/Http/Requests/Api/Contacts/UpsertContactsRequest.php
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Api\Contacts;
|
||||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\InputData;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Kwaadpepper\Enum\Rules\EnumIsValidRule;
|
||||
|
||||
class UpsertContactsRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
// * Check is done with api.token middleware
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation()
|
||||
{
|
||||
$this->merge([
|
||||
'contacts' => \collect($this->contacts)->filter()
|
||||
->map(function ($contact) {
|
||||
$contact = \collect($contact);
|
||||
if ($contact->has('data')) {
|
||||
$contact->put('data', \collect($contact->get('data'))->all());
|
||||
$contact->put('dataParsed', \collect($contact->get('data'))
|
||||
->map(function ($value, $index) {
|
||||
return \call_user_func([$this, 'filterDataLine'], $value, $index);
|
||||
})
|
||||
->filter()->all());
|
||||
}
|
||||
if ($contact->has('visits')) {
|
||||
$contact->put('visits', \collect($contact->get('visits'))->filter()
|
||||
->map(function ($visit) {
|
||||
if (!\is_array($visit)) {
|
||||
return $visit;
|
||||
}
|
||||
$visit = \collect($visit);
|
||||
$visit->put('note', $visit->get('note') ?? '');
|
||||
return $visit->all();
|
||||
})->all());
|
||||
}
|
||||
return $contact->all();
|
||||
})->all()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'contacts' => 'present|array',
|
||||
'contacts.*' => 'array',
|
||||
'contacts.*.id' => 'nullable|uuid|exists:contacts,id',
|
||||
'contacts.*.name' => 'required|string|max:255',
|
||||
'contacts.*.firstname' => 'required|string|max:255',
|
||||
// * Dot not validate email here (soft validate), if it does not pass, app will be blocked.
|
||||
'contacts.*.email' => 'required|string|max:255',
|
||||
'contacts.*.phone' => 'required|string|max:255',
|
||||
|
||||
// * DATA
|
||||
'contacts.*.data' => 'present|array',
|
||||
'contacts.*.dataParsed' => 'present',
|
||||
'contacts.*.data.*' => 'array',
|
||||
'contacts.*.data.*.title' => 'present|string|min:1',
|
||||
'contacts.*.data.*.type' => ['present', new EnumIsValidRule(InputTypeEnum::class)],
|
||||
'contacts.*.data.*.value' => 'present',
|
||||
'contacts.*.data.*.required' => 'present|boolean',
|
||||
|
||||
'contacts.*.notes' => 'nullable|string',
|
||||
'contacts.*.visits' => 'present|array',
|
||||
'contacts.*.visits.*' => 'required|array',
|
||||
'contacts.*.visits.*.title' => 'present|string',
|
||||
'contacts.*.visits.*.note' => 'present|string',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a line of data (input)
|
||||
*
|
||||
* @param array $data
|
||||
* @param mixed $index
|
||||
* @return mixed
|
||||
* @throws \Illuminate\Validation\ValidationException In case of parse failure.
|
||||
*/
|
||||
private function filterDataLine(array $data, $index)
|
||||
{
|
||||
$data = \collect($data);
|
||||
try {
|
||||
$title = $data->get('title') ? \strval($data->get('title')) : null;
|
||||
if (\is_null($title)) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => "wrong title on data index '{$index}'"
|
||||
]);
|
||||
}
|
||||
$type = InputTypeEnum::make($data->get('type') ? $data->get('type') : null);
|
||||
$value = $data['value'] ?? null;
|
||||
$required = $data->get('required') ? true : false;
|
||||
$inputClass = $type->inputClass;
|
||||
return $inputClass::from(InputData::make(
|
||||
$title,
|
||||
$type,
|
||||
$value,
|
||||
$required
|
||||
), $required);
|
||||
} catch (\TypeError | \BadMethodCallException $e) {
|
||||
throw ValidationException::withMessages([
|
||||
'error' => "wrong type on data index '{$index}'"
|
||||
]);
|
||||
} catch (\RuntimeException $e) {
|
||||
$message = $e->getMessage();
|
||||
throw ValidationException::withMessages([
|
||||
'error' => "wrong data on index '{$index}' '{$message}'"
|
||||
]);
|
||||
} //end try
|
||||
}
|
||||
}
|
||||
|
|
@ -39,6 +39,7 @@ class StoreFormularyRequest extends FormRequest
|
|||
*/
|
||||
public function rules()
|
||||
{
|
||||
// FIXME: details has to be validated.
|
||||
$rules = [
|
||||
'type' => ['required', new EnumIsValidRule(InputTypeEnum::class)],
|
||||
'placeholder' => 'present|array',
|
||||
|
|
|
|||
|
|
@ -17,25 +17,20 @@ class ContactResource extends JsonResource
|
|||
public function toArray($request)
|
||||
{
|
||||
//phpcs:enable
|
||||
/** @var \App\Models\Contact */
|
||||
$contact = $this;
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'email' => $this->email,
|
||||
'type' => $this->type,
|
||||
'other' => $this->other,
|
||||
'select1' => $this->select1,
|
||||
'select2' => $this->select2,
|
||||
'name' => $this->lastname,
|
||||
'firstname' => $this->firstname,
|
||||
'company' => $this->company,
|
||||
'address' => $this->address,
|
||||
'phone' => $this->phone,
|
||||
'products' => $this->products,
|
||||
'card_url' => $this->card_url,
|
||||
'notes' => $this->notes,
|
||||
'visits' => $this->visits,
|
||||
'user_id' => $this->app_user_id,
|
||||
'created_at' => $this->created_at,
|
||||
'updated_at' => $this->updated_at,
|
||||
'id' => $contact->id,
|
||||
'name' => $contact->lastname,
|
||||
'firstname' => $contact->firstname,
|
||||
'email' => $contact->email,
|
||||
'phone' => $contact->phone,
|
||||
'data' => $contact->data,
|
||||
'notes' => $contact->notes,
|
||||
'visits' => $contact->visits,
|
||||
'app_user_id' => $contact->app_user_id,
|
||||
'created_at' => $contact->created_at,
|
||||
'updated_at' => $contact->updated_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
141
app/Lib/Inputs/Definition/Input.php
Normal file
141
app/Lib/Inputs/Definition/Input.php
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Inputs\Definition;
|
||||
|
||||
/**
|
||||
* To manipulate Input
|
||||
*
|
||||
* @property-read \App\Lib\Inputs\Definition\InputData $data The input type data.
|
||||
* @package App\Lib\Inputs
|
||||
*/
|
||||
abstract class Input implements InputInterface
|
||||
{
|
||||
/**
|
||||
* The Input Type.
|
||||
*
|
||||
* @var \App\Lib\Inputs\Definition\InputData
|
||||
*/
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \App\Lib\Inputs\Definition\InputData $data
|
||||
* @param boolean $required
|
||||
* @return void
|
||||
* @throws \RuntimeException If $data is wrong.
|
||||
*/
|
||||
public function __construct(InputData $data, bool $required = true)
|
||||
{
|
||||
InputData::assertIsInputTypeData($data);
|
||||
static::validateData($data->value, $required);
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this input required ?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isRequired(): bool
|
||||
{
|
||||
return $this->data->required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse DB line to Object
|
||||
*
|
||||
* ! Need to validate inputType
|
||||
*
|
||||
* @param \App\Lib\Inputs\Definition\InputData $data
|
||||
* @param boolean $required
|
||||
* @return static
|
||||
* @throws \RuntimeException If the input type is not recognized, or data is invalid.
|
||||
*/
|
||||
public static function from(InputData $data, bool $required = true)
|
||||
{
|
||||
$inputTypeDataClass = static::class;
|
||||
try {
|
||||
$type = \is_numeric($data->type) ? intval($data->type) : strval($data->type);
|
||||
return new static(InputData::make($data->title, $type, $data->value, $required), $required);
|
||||
} catch (\BadMethodCallException $e) {
|
||||
throw new \RuntimeException("Could not instanciate {$type}");
|
||||
} catch (\Illuminate\Validation\ValidationException $e) {
|
||||
$encodedData = \json_encode($data);
|
||||
throw new \RuntimeException("Data does not comply with {$inputTypeDataClass}, given {$encodedData}");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse DB line to Object
|
||||
*
|
||||
* ! Need to validate inputType
|
||||
*
|
||||
* @param string $title The line placeholder.
|
||||
* @param string|array $data The line with data.
|
||||
* @param boolean $required The line is required.
|
||||
* @return static
|
||||
* @throws \RuntimeException If the input type is not recognized, or data is invalid.
|
||||
*/
|
||||
public static function make(string $title, $data, bool $required = true)
|
||||
{
|
||||
return static::from(
|
||||
InputData::make(
|
||||
$title,
|
||||
static::getType()->value,
|
||||
$data,
|
||||
$required
|
||||
),
|
||||
$required
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate data using getValidator instance
|
||||
*
|
||||
* @param string|array $data The line with data.
|
||||
* @param boolean $required The line is required.
|
||||
* @return void
|
||||
* @throws \Illuminate\Validation\ValidationException If the data is invalid.
|
||||
*/
|
||||
public static function validateData($data, bool $required): void
|
||||
{
|
||||
static::getValidator($data, $required)->validate();
|
||||
}
|
||||
|
||||
// * TRANSFORMERS
|
||||
|
||||
/**
|
||||
* Get the instance as an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return (array)$this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the object to its JSON representation.
|
||||
*
|
||||
* @param integer $options
|
||||
* @return string
|
||||
* @phpcs:disable Squiz.Commenting.FunctionComment.ScalarTypeHintMissing
|
||||
*/
|
||||
public function toJson($options = 0)
|
||||
{
|
||||
// phpcs:enable
|
||||
return \json_encode($this->jsonSerialize(), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the object into something JSON serializable.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->toArray();
|
||||
}
|
||||
}
|
||||
93
app/Lib/Inputs/Definition/InputData.php
Normal file
93
app/Lib/Inputs/Definition/InputData.php
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Inputs\Definition;
|
||||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
|
||||
/**
|
||||
* @property-read string $title The input type placeholder
|
||||
* @property-read integer $type The input type value
|
||||
* @property-read string|array<integer,string> $value The input value, either a string or an array
|
||||
* with the value index and label
|
||||
* (for Multiselect and checkboxes)
|
||||
* @property-read boolean $required The input is required ?
|
||||
* @package App\Lib\Inputs
|
||||
*/
|
||||
class InputData extends \stdClass
|
||||
{
|
||||
/**
|
||||
* Get property
|
||||
*
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
* @throws \TypeError If prop is undefined.
|
||||
*/
|
||||
public function __get(string $name): mixed
|
||||
{
|
||||
if (in_array($name, ['title', 'type', 'value', 'required'])) {
|
||||
return $this->{$name};
|
||||
}
|
||||
throw new \TypeError("undefined property {$name}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Make and instance
|
||||
*
|
||||
* @param string $title
|
||||
* @param \App\Enums\Formularies\InputTypeEnum|integer $type
|
||||
* @param string|array<integer,string> $data
|
||||
* @param boolean $required
|
||||
* @return \App\Lib\Inputs\Definition\InputData
|
||||
* @throws \RuntimeException If $type or $data is wrong.
|
||||
*/
|
||||
public static function make(string $title, $type, $data, bool $required): self
|
||||
{
|
||||
$ipTypeData = new self();
|
||||
$ipTypeData->title = $title;
|
||||
$ipTypeData->type = (\is_object($type) and \get_class($type) === InputTypeEnum::class) ?
|
||||
$type->value : $type;
|
||||
$ipTypeData->value = $data;
|
||||
$ipTypeData->required = $required;
|
||||
self::assertIsInputTypeData($ipTypeData);
|
||||
return $ipTypeData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm $data is of type InputTypeData
|
||||
*
|
||||
* @param \App\Lib\Inputs\Definition\InputData $data
|
||||
* @return void
|
||||
* @throws \RuntimeException If $data is wrong.
|
||||
*/
|
||||
public static function assertIsInputTypeData(InputData $data)
|
||||
{
|
||||
$title = $data->title;
|
||||
$type = $data->type;
|
||||
$value = $data->value;
|
||||
$required = $data->required;
|
||||
|
||||
if (!\is_string($title)) {
|
||||
throw new \RuntimeException("InputTypeData 'title' should be a string");
|
||||
}
|
||||
if (!\is_integer($type)) {
|
||||
throw new \RuntimeException("InputTypeData 'type' should be an integer");
|
||||
}
|
||||
if (!\is_bool($required)) {
|
||||
throw new \RuntimeException("InputTypeData 'required' should be a boolean");
|
||||
}
|
||||
|
||||
try {
|
||||
$type = InputTypeEnum::make($type);
|
||||
} catch (\BadMethodCallException $e) {
|
||||
throw new \RuntimeException($e->getMessage());
|
||||
}
|
||||
|
||||
if (!\is_null($value) && !\is_string($value) && !\is_array($value)) {
|
||||
$type = \gettype($value);
|
||||
$value = \json_encode($value);
|
||||
throw new \RuntimeException(
|
||||
"InputTypeData 'value' should be string or array given '{$value}' of type '{$type}'"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
82
app/Lib/Inputs/Definition/InputInterface.php
Normal file
82
app/Lib/Inputs/Definition/InputInterface.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Inputs\Definition;
|
||||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use Illuminate\Contracts\Support\Arrayable;
|
||||
use Illuminate\Contracts\Support\Jsonable;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
|
||||
/**
|
||||
* @package App\Lib\Inputs
|
||||
*/
|
||||
interface InputInterface extends Jsonable, Arrayable, \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \App\Lib\Inputs\Definition\InputData $data
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(InputData $data);
|
||||
|
||||
/**
|
||||
* Parse DB line to Object
|
||||
*
|
||||
* ! Need to validate inputType
|
||||
*
|
||||
* @param \App\Lib\Inputs\Definition\InputData $data
|
||||
* @param boolean $required
|
||||
* @return static
|
||||
* @throws \RuntimeException If the input type is not recognized, or data is invalid.
|
||||
*/
|
||||
public static function from(InputData $data, bool $required = true);
|
||||
|
||||
/**
|
||||
* Parse DB line to Object
|
||||
*
|
||||
* ! Need to validate inputType
|
||||
*
|
||||
* @param string $title The line placeholder.
|
||||
* @param string|array $data The line with data.
|
||||
* @param boolean $required The line is required.
|
||||
* @return static
|
||||
* @throws \RuntimeException If the input type is not recognized, or data is invalid.
|
||||
*/
|
||||
public static function make(string $title, $data, bool $required = true);
|
||||
|
||||
// * --- CHILDS Should implement ---
|
||||
|
||||
/**
|
||||
* Is this input required ?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isRequired(): bool;
|
||||
|
||||
/**
|
||||
* Get the matching enum for this object
|
||||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum;
|
||||
|
||||
/**
|
||||
* Get the validator this input
|
||||
*
|
||||
* @param string|array $data The line with data.
|
||||
* @param boolean $required The line is required.
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
public static function getValidator($data, bool $required): Validator;
|
||||
|
||||
/**
|
||||
* Validate data using getValidator instance
|
||||
*
|
||||
* @param string|array $data The line with data.
|
||||
* @param boolean $required The line is required.
|
||||
* @return string|array<integer,string>
|
||||
* @throws \Illuminate\Validation\ValidationException If the data is invalid.
|
||||
*/
|
||||
public static function validateData($data, bool $required);
|
||||
}
|
||||
44
app/Lib/Inputs/InputCheckbox.php
Normal file
44
app/Lib/Inputs/InputCheckbox.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Inputs;
|
||||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\Input;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Support\Facades\Validator as FacadesValidator;
|
||||
|
||||
/**
|
||||
* @inheritDoc Checkbox
|
||||
* @package App\Lib\Inputs
|
||||
*/
|
||||
class InputCheckbox extends Input
|
||||
{
|
||||
/**
|
||||
* Get the matching enum for this object
|
||||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum
|
||||
{
|
||||
return InputTypeEnum::checkbox();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the validator this input
|
||||
*
|
||||
* @param string|array $data The line with data.
|
||||
* @param boolean $required The line is required.
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
public static function getValidator($data, bool $required): Validator
|
||||
{
|
||||
return FacadesValidator::make(
|
||||
['value' => $data],
|
||||
[
|
||||
'value' => 'array' . ($required ? '|min:1' : ''),
|
||||
'value.*' => 'required|string|max:255'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
41
app/Lib/Inputs/InputEmail.php
Normal file
41
app/Lib/Inputs/InputEmail.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Inputs;
|
||||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\Input;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Support\Facades\Validator as FacadesValidator;
|
||||
|
||||
/**
|
||||
* @inheritDoc Email
|
||||
* @package App\Lib\Inputs
|
||||
*/
|
||||
class InputEmail extends Input
|
||||
{
|
||||
/**
|
||||
* Get the matching enum for this object
|
||||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum
|
||||
{
|
||||
return InputTypeEnum::email();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the validator this input
|
||||
*
|
||||
* @param string|array $data The line with data.
|
||||
* @param boolean $required The line is required.
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
public static function getValidator($data, bool $required): Validator
|
||||
{
|
||||
return FacadesValidator::make(
|
||||
['value' => $data],
|
||||
['value' => ($required ? 'required' : 'nullable') . '|string|email:rfc,spoof|max:255']
|
||||
);
|
||||
}
|
||||
}
|
||||
41
app/Lib/Inputs/InputPhone.php
Normal file
41
app/Lib/Inputs/InputPhone.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Inputs;
|
||||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\Input;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Support\Facades\Validator as FacadesValidator;
|
||||
|
||||
/**
|
||||
* @inheritDoc Phone
|
||||
* @package App\Lib\Inputs
|
||||
*/
|
||||
class InputPhone extends Input
|
||||
{
|
||||
/**
|
||||
* Get the matching enum for this object
|
||||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum
|
||||
{
|
||||
return InputTypeEnum::phone();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the validator this input
|
||||
*
|
||||
* @param string|array $data The line with data.
|
||||
* @param boolean $required The line is required.
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
public static function getValidator($data, bool $required): Validator
|
||||
{
|
||||
return FacadesValidator::make(
|
||||
['value' => $data],
|
||||
['value' => ($required ? 'required' : 'nullable') . '|string|max:255']
|
||||
);
|
||||
}
|
||||
}
|
||||
41
app/Lib/Inputs/InputRadio.php
Normal file
41
app/Lib/Inputs/InputRadio.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Inputs;
|
||||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\Input;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Support\Facades\Validator as FacadesValidator;
|
||||
|
||||
/**
|
||||
* @inheritDoc Radio
|
||||
* @package App\Lib\Inputs
|
||||
*/
|
||||
class InputRadio extends Input
|
||||
{
|
||||
/**
|
||||
* Get the matching enum for this object
|
||||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum
|
||||
{
|
||||
return InputTypeEnum::radio();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the validator this input
|
||||
*
|
||||
* @param string|array $data The line with data.
|
||||
* @param boolean $required The line is required.
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
public static function getValidator($data, bool $required): Validator
|
||||
{
|
||||
return FacadesValidator::make(
|
||||
['value' => $data],
|
||||
['value' => ($required ? 'required' : 'nullable') . '|string|max:255']
|
||||
);
|
||||
}
|
||||
}
|
||||
41
app/Lib/Inputs/InputSelect.php
Normal file
41
app/Lib/Inputs/InputSelect.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Inputs;
|
||||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\Input;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Support\Facades\Validator as FacadesValidator;
|
||||
|
||||
/**
|
||||
* @inheritDoc Select
|
||||
* @package App\Lib\Inputs
|
||||
*/
|
||||
class InputSelect extends Input
|
||||
{
|
||||
/**
|
||||
* Get the matching enum for this object
|
||||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum
|
||||
{
|
||||
return InputTypeEnum::select();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the validator this input
|
||||
*
|
||||
* @param string|array $data The line with data.
|
||||
* @param boolean $required The line is required.
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
public static function getValidator($data, bool $required): Validator
|
||||
{
|
||||
return FacadesValidator::make(
|
||||
['value' => $data],
|
||||
['value' => ($required ? 'required' : 'nullable') . '|string|max:255']
|
||||
);
|
||||
}
|
||||
}
|
||||
22
app/Lib/Inputs/InputSelectMultiple.php
Normal file
22
app/Lib/Inputs/InputSelectMultiple.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Inputs;
|
||||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
|
||||
/**
|
||||
* @inheritDoc SelectMultiple
|
||||
* @package App\Lib\Inputs
|
||||
*/
|
||||
class InputSelectMultiple extends InputCheckbox
|
||||
{
|
||||
/**
|
||||
* Get the matching enum for this object
|
||||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum
|
||||
{
|
||||
return InputTypeEnum::selectMultiple();
|
||||
}
|
||||
}
|
||||
40
app/Lib/Inputs/InputText.php
Normal file
40
app/Lib/Inputs/InputText.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib\Inputs;
|
||||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\Input;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use Illuminate\Support\Facades\Validator as FacadesValidator;
|
||||
|
||||
/**
|
||||
* @package App\Lib\Inputs
|
||||
*/
|
||||
class InputText extends Input
|
||||
{
|
||||
/**
|
||||
* Get the matching enum for this object
|
||||
*
|
||||
* @return \App\Enums\Formularies\InputTypeEnum
|
||||
*/
|
||||
public static function getType(): InputTypeEnum
|
||||
{
|
||||
return InputTypeEnum::text();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the validator this input
|
||||
*
|
||||
* @param string|array $data The line with data.
|
||||
* @param boolean $required The line is required.
|
||||
* @return \Illuminate\Contracts\Validation\Validator
|
||||
*/
|
||||
public static function getValidator($data, bool $required): Validator
|
||||
{
|
||||
return FacadesValidator::make(
|
||||
['value' => $data],
|
||||
['value' => ($required ? 'required' : 'nullable') . '|string|max:255']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,30 +2,31 @@
|
|||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Casts\AsArrayOfInput;
|
||||
use App\Lib\Inputs\InputEmail;
|
||||
use App\Lib\Inputs\InputPhone;
|
||||
use App\Lib\Inputs\InputText;
|
||||
use App\Traits\Models\HasUuidKey;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Kwaadpepper\Enum\Traits\CastsEnums;
|
||||
|
||||
/**
|
||||
* @property integer $app_user_id
|
||||
* @property integer $id
|
||||
* @property string $id
|
||||
* @property string $email
|
||||
* @property string $type
|
||||
* @property string $other
|
||||
* @property string $select1
|
||||
* @property string $select2
|
||||
* @property string $name
|
||||
* @property string $lastname
|
||||
* @property string $firstname
|
||||
* @property string $company
|
||||
* @property string $address
|
||||
* @property string $phone
|
||||
* @property string $products
|
||||
* @property string $card_url
|
||||
* @property array<\App\Lib\Inputs\Definition\Input> $data
|
||||
* @property string $notes
|
||||
* @property string $visits
|
||||
*/
|
||||
class Contact extends Model
|
||||
{
|
||||
use CastsEnums;
|
||||
use HasFactory;
|
||||
use HasUuidKey;
|
||||
|
||||
/**
|
||||
* fillable
|
||||
|
|
@ -34,21 +35,24 @@ class Contact extends Model
|
|||
protected $fillable = [
|
||||
'app_user_id',
|
||||
'email',
|
||||
'type',
|
||||
'other',
|
||||
'select1',
|
||||
'select2',
|
||||
'name',
|
||||
'lastname',
|
||||
'firstname',
|
||||
'company',
|
||||
'address',
|
||||
'data',
|
||||
'phone',
|
||||
'products',
|
||||
'card_url',
|
||||
'notes',
|
||||
'visits',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'data' => AsArrayOfInput::class,
|
||||
'visits' => 'array'
|
||||
];
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
|
|
@ -58,6 +62,40 @@ class Contact extends Model
|
|||
*/
|
||||
public function appUser()
|
||||
{
|
||||
return $this->belongsTo(AppUser::class, 'id', 'app_user_id');
|
||||
return $this->belongsTo(AppUser::class, 'app_user_id', 'id');
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Get all inputs
|
||||
*
|
||||
* @return array
|
||||
* @throws \RuntimeException This should not happen since data was validated on contact insertion.
|
||||
* ! It may happen if this model does not have an email.
|
||||
* ! It may only happen if input validation rules are changed.
|
||||
*/
|
||||
public function allInputs(): array
|
||||
{
|
||||
return $this->mandatoryInputs() + $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mandatory inputs
|
||||
*
|
||||
* @return array<\App\Lib\Inputs\Definition\Input>
|
||||
* @throws \RuntimeException If this model does have an email.
|
||||
*/
|
||||
public function mandatoryInputs(): array
|
||||
{
|
||||
// * firsname
|
||||
$data[] = InputText::make('Prénom', $this->firstname, false);
|
||||
// * lastname
|
||||
$data[] = InputText::make('Nom', $this->lastname, false);
|
||||
// * email
|
||||
$data[] = InputEmail::make('E-mail', $this->email, true);
|
||||
// * phone
|
||||
$data[] = InputPhone::make('Téléphone', $this->phone, false);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class AppServiceProvider extends ServiceProvider
|
|||
public function boot()
|
||||
{
|
||||
// * HTTPS FIX
|
||||
URL::forceScheme('https');
|
||||
// URL::forceScheme('http');
|
||||
|
||||
// * HA PROXY FIX
|
||||
App::singleton('clientIp', function () {
|
||||
|
|
|
|||
43
app/Traits/Models/HasUuidKey.php
Normal file
43
app/Traits/Models/HasUuidKey.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace App\Traits\Models;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
trait HasUuidKey
|
||||
{
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
parent::booted();
|
||||
static::creating(function ($model) {
|
||||
if (empty($model->{$model->getKeyName()})) {
|
||||
$model->{$model->getKeyName()} = Str::uuid()->toString();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value indicating whether the IDs are incrementing.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function getIncrementing()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the auto-incrementing key type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getKeyType()
|
||||
{
|
||||
return 'string';
|
||||
}
|
||||
}
|
||||
|
|
@ -196,6 +196,6 @@ return [
|
|||
|
|
||||
*/
|
||||
|
||||
'same_site' => 'lax',
|
||||
'same_site' => null,
|
||||
|
||||
];
|
||||
|
|
|
|||
81
database/factories/ContactFactory.php
Normal file
81
database/factories/ContactFactory.php
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\Formularies\InputTypeEnum;
|
||||
use App\Lib\Inputs\Definition\InputData;
|
||||
use App\Models\Contact;
|
||||
use App\Models\Formulary;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class ContactFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Contact::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Formulary> */
|
||||
$formularies = $this->factoryForModel(Formulary::class)->count($this->faker->numberBetween(3, 9))->make();
|
||||
return [
|
||||
'email' => $this->faker->unique()->email(),
|
||||
'lastname' => $this->faker->boolean() ? $this->faker->unique()->lastName() : '',
|
||||
'firstname' => $this->faker->boolean() ? $this->faker->unique()->firstName() : '',
|
||||
'phone' => $this->faker->boolean() ? $this->faker->unique()->phoneNumber() : '',
|
||||
'notes' => $this->faker->boolean() ? $this->faker->text() : null,
|
||||
'visits' => \collect(range(0, $this->faker->numberBetween(1, 5)))->mapWithKeys(function () {
|
||||
return [
|
||||
'title' => 'Visite du ' . $this->faker->dateTime()->format('D/M/Y H:i'),
|
||||
'note' => $this->faker->text()
|
||||
];
|
||||
}),
|
||||
'data' => $formularies->map(function (Formulary $formulary) {
|
||||
$inputClass = $formulary->type->inputClass;
|
||||
$details = \collect($formulary->details)->map(function (array $details) {
|
||||
return $details['fr'];
|
||||
});
|
||||
|
||||
$data = $this->faker->words(3, true);
|
||||
|
||||
if ($formulary->type->equals(InputTypeEnum::email())) {
|
||||
$data = $this->faker->unique()->email();
|
||||
}
|
||||
if ($formulary->type->equals(InputTypeEnum::phone())) {
|
||||
$data = $this->faker->phoneNumber();
|
||||
}
|
||||
if (
|
||||
in_array($formulary->type->value, [
|
||||
InputTypeEnum::selectMultiple()->value,
|
||||
InputTypeEnum::checkbox()->value
|
||||
])
|
||||
) {
|
||||
$data = \collect($details->random(min($details->count(), 2)))->all();
|
||||
}
|
||||
if (
|
||||
in_array($formulary->type->value, [
|
||||
InputTypeEnum::select()->value,
|
||||
InputTypeEnum::radio()->value
|
||||
])
|
||||
) {
|
||||
$data = $details->random();
|
||||
}
|
||||
|
||||
return $inputClass::from(InputData::make(
|
||||
$formulary->placeholder['fr'],
|
||||
$formulary->type,
|
||||
$data,
|
||||
$formulary->required
|
||||
), $formulary->required);
|
||||
})
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ class FormularyFactory extends Factory
|
|||
$details = null;
|
||||
if (
|
||||
\in_array($type, [
|
||||
InputTypeEnum::multipleselect(), InputTypeEnum::select(),
|
||||
InputTypeEnum::selectMultiple(), InputTypeEnum::select(),
|
||||
InputTypeEnum::radio(), InputTypeEnum::checkbox()
|
||||
])
|
||||
) {
|
||||
|
|
|
|||
272
database/migrations/2023_08_25_093125_upgrade_contacts_table.php
Normal file
272
database/migrations/2023_08_25_093125_upgrade_contacts_table.php
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
<?php
|
||||
|
||||
use App\Lib\Inputs\InputCheckbox;
|
||||
use App\Lib\Inputs\InputSelect;
|
||||
use App\Lib\Inputs\InputText;
|
||||
use App\Models\Contact;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class UpgradeContactsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
DB::transaction(function () {
|
||||
$oldContacts = DB::table('contacts')->get();
|
||||
/**
|
||||
* Keep columns, id, notes, visits, app_user_id
|
||||
*/
|
||||
Schema::table('contacts', function (Blueprint $table) {
|
||||
$table->dropColumn('type');
|
||||
$table->dropColumn('other');
|
||||
$table->dropColumn('select1');
|
||||
$table->dropColumn('select2');
|
||||
$table->dropColumn('company');
|
||||
$table->dropColumn('address');
|
||||
$table->dropColumn('products');
|
||||
// * Just forget this column, dont migrate.
|
||||
$table->dropColumn('card_url');
|
||||
$table->json('data')->after('phone')
|
||||
->comment('Array of \App\Lib\Inputs\Definition\InputData');
|
||||
});
|
||||
|
||||
$oldContacts->each(function (object $table) {
|
||||
$contact = Contact::query()->where('id', $table->id)->firstOrFail();
|
||||
|
||||
// ! see this->getDataset.
|
||||
$contact->data = $this->getInputs($table);
|
||||
$contact->saveQuietly();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
* @throws \RuntimeException Wont undo that.
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
throw new \RuntimeException('Wont undo that');
|
||||
}
|
||||
|
||||
/**
|
||||
* Map $table to an array of inputs
|
||||
*
|
||||
* @param object $table
|
||||
* @return array<\App\Lib\Inputs\Definition\Input>
|
||||
*/
|
||||
private function getInputs(object $table): array
|
||||
{
|
||||
/**
|
||||
* Migrate other columns type, other, select1, select2, company, address, products
|
||||
*/
|
||||
|
||||
// * type
|
||||
$data[] = InputSelect::make(
|
||||
'Type de client',
|
||||
([
|
||||
'client' => 'Client', 'prospect' => 'Prospect', 'other' => 'Autre'
|
||||
])[$table->type]
|
||||
);
|
||||
// * other
|
||||
$data[] = InputText::make('Type de client (autre) :', $table->other, false);
|
||||
// * select1
|
||||
$dataset = $this->getDataset('select1');
|
||||
$data[] = InputSelect::make($dataset['title']['fr'], $dataset['values'][$table->select1]['fr'] ?? null, false);
|
||||
// * select2
|
||||
$dataset = $this->getDataset('select2');
|
||||
$data[] = InputSelect::make($dataset['title']['fr'], $dataset['values'][$table->select2]['fr'] ?? null, false);
|
||||
// * company
|
||||
$data[] = InputText::make('Société', $table->company, false);
|
||||
// * address
|
||||
$data[] = InputText::make('Adresse', $table->address, false);
|
||||
// * products
|
||||
$dataset = collect($this->getDataset('products'))->map(function (array $prodLangs) {
|
||||
return $prodLangs['fr'];
|
||||
})->all();
|
||||
$data[] = InputCheckbox::make(
|
||||
'Produits',
|
||||
collect(json_decode($table->products, true))
|
||||
->map(function ($hasProduct, int $index) use ($dataset) {
|
||||
return $hasProduct ? $dataset[$index] : null;
|
||||
})->filter()->values()->all(),
|
||||
false
|
||||
);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get App RHD fields
|
||||
*
|
||||
* ! This should be customized for the APP, here done for : APP_RHD
|
||||
* ! CUSTOMIZE ME en fonction de l'app !
|
||||
*
|
||||
* @param string $dataSet
|
||||
* @return array
|
||||
* @throws \Error IF dataset is unkown.
|
||||
*/
|
||||
private function getDataset(string $dataSet): array
|
||||
{
|
||||
$json = '';
|
||||
switch ($dataSet) {
|
||||
case 'select1':
|
||||
$json = '{
|
||||
"title": {
|
||||
"fr": "Travaille avec",
|
||||
"en": "Work with",
|
||||
"de": "Arbeit mit"
|
||||
},
|
||||
"values": {
|
||||
"pole-sable": {
|
||||
"fr": "P\u00f4le Sabl\u00e9",
|
||||
"en": "P\u00f4le Sabl\u00e9",
|
||||
"de": "P\u00f4le Sabl\u00e9"
|
||||
},
|
||||
"snv": {
|
||||
"fr": "SNV",
|
||||
"en": "SNV",
|
||||
"de": "SNV"
|
||||
},
|
||||
"pole-sud-est": {
|
||||
"fr": "P\u00f4le Sud-Est",
|
||||
"en": "P\u00f4le Sud-Est",
|
||||
"de": "P\u00f4le Sud-Est"
|
||||
},
|
||||
"aquitaine": {
|
||||
"fr": "Aquitaine",
|
||||
"en": "Aquitaine",
|
||||
"de": "Aquitaine"
|
||||
},
|
||||
"sbv": {
|
||||
"fr": "SBV",
|
||||
"en": "SBV",
|
||||
"de": "SBV"
|
||||
},
|
||||
"arrive": {
|
||||
"fr": "Arriv\u00e9",
|
||||
"en": "Arriv\u00e9",
|
||||
"de": "Arriv\u00e9"
|
||||
},
|
||||
"plusieurs-filiales": {
|
||||
"fr": "Plusieurs filiales",
|
||||
"en": "Several subsidiaries",
|
||||
"de": "Mehrere Filialen"
|
||||
},
|
||||
"autre": {
|
||||
"fr": "Autre",
|
||||
"en": "Other",
|
||||
"de": "Andere"
|
||||
}
|
||||
}
|
||||
}';
|
||||
break;
|
||||
case 'select2':
|
||||
$json = '{
|
||||
"title": {
|
||||
"fr": "Type de commerce",
|
||||
"en": "Type of business",
|
||||
"de": "Art des Gesch\u00e4fts"
|
||||
},
|
||||
"values": {
|
||||
"commerce-de-detail": {
|
||||
"fr": "Commerce de d\u00e9tail",
|
||||
"en": "Retail trade",
|
||||
"de": "Einzelhandel"
|
||||
},
|
||||
"restauration-commerciale": {
|
||||
"fr": "Restauration Commerciale",
|
||||
"en": "Commercial catering",
|
||||
"de": "Kommerzielle Restauration"
|
||||
},
|
||||
"restauration-collective": {
|
||||
"fr": "Restauration Collective",
|
||||
"en": "Collective catering",
|
||||
"de": "Kollektiv Restauration"
|
||||
},
|
||||
"grossiste-distributeur-cash": {
|
||||
"fr": "Grossiste Distributeur Cash",
|
||||
"en": "Wholesale Distributor Cash",
|
||||
"de": "Gro\u00dfh\u00e4ndler H\u00e4ndler Cash"
|
||||
},
|
||||
"pai": {
|
||||
"fr": "PAI",
|
||||
"en": "PAI",
|
||||
"de": "PAI"
|
||||
},
|
||||
"home-freezer-center": {
|
||||
"fr": "Home Freezer Center",
|
||||
"en": "Home Freezer Center",
|
||||
"de": "Home Gefrierzentrum"
|
||||
},
|
||||
"autres": {
|
||||
"fr": "Autre",
|
||||
"en": "Other",
|
||||
"de": "Andere"
|
||||
}
|
||||
}
|
||||
}';
|
||||
break;
|
||||
case 'products':
|
||||
$json = '[
|
||||
{
|
||||
"fr": "Frais",
|
||||
"en": "Fresh",
|
||||
"de": "Frisch"
|
||||
},
|
||||
{
|
||||
"fr": "Surgel\u00e9s",
|
||||
"en": "Frozen food",
|
||||
"de": "Tiefk\u00fchlkost"
|
||||
},
|
||||
{
|
||||
"fr": "Volailles crues",
|
||||
"en": "Raw poultry",
|
||||
"de": "Rohes Gefl\u00fcgel"
|
||||
},
|
||||
{
|
||||
"fr": "\u00c9labor\u00e9s crus",
|
||||
"en": "Prepared raw",
|
||||
"de": "Roh ausgearbeitet"
|
||||
},
|
||||
{
|
||||
"fr": "\u00c9labor\u00e9s cuits",
|
||||
"en": "Cooked products",
|
||||
"de": "Gekochte Elaborate"
|
||||
},
|
||||
{
|
||||
"fr": "Bio et Label Rouge",
|
||||
"en": "Bio and Label Rouge",
|
||||
"de": "Bio und Label Rouge"
|
||||
},
|
||||
{
|
||||
"fr": "BBC",
|
||||
"en": "BBC",
|
||||
"de": "BBC"
|
||||
},
|
||||
{
|
||||
"fr": "Halal",
|
||||
"en": "Halal",
|
||||
"de": "Halal"
|
||||
},
|
||||
{
|
||||
"fr": "Autre",
|
||||
"en": "Other",
|
||||
"de": "Andere"
|
||||
}
|
||||
]';
|
||||
break;
|
||||
default:
|
||||
throw new \Error('unkonwn dataset');
|
||||
} //end switch
|
||||
return json_decode($json, true);
|
||||
}
|
||||
}
|
||||
|
|
@ -14,10 +14,10 @@ class AppUserSeeder extends Seeder
|
|||
*/
|
||||
public function run()
|
||||
{
|
||||
$i = 1;
|
||||
AppUser::factory(15)->make()->each(function (AppUser $directory) use (&$i) {
|
||||
$directory->order = $i;
|
||||
$directory->saveOrFail();
|
||||
$i = \intval(AppUser::query()->max('order'));
|
||||
AppUser::factory(15)->make()->each(function (AppUser $appUser) use (&$i) {
|
||||
$appUser->order = $i;
|
||||
$appUser->saveOrFail();
|
||||
$i = $i + 1;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
30
database/seeders/ContactSeeder.php
Normal file
30
database/seeders/ContactSeeder.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\AppUser;
|
||||
use App\Models\Contact;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ContactSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
DB::table((new Contact())->getTable())->truncate();
|
||||
$appUsers = AppUser::all();
|
||||
if (!$appUsers->count()) {
|
||||
$this->run(AppUser::class);
|
||||
$appUsers = AppUser::all();
|
||||
}
|
||||
Contact::factory(30)->make()->each(function (Contact $contact) use ($appUsers) {
|
||||
$contact->appUser()->associate($appUsers->random());
|
||||
$contact->saveOrFail();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ class DatabaseSeeder extends Seeder
|
|||
SettingSeeder::class,
|
||||
TagSeeder::class,
|
||||
FormularySeeder::class,
|
||||
ContactSeeder::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ class FormularySeeder extends Seeder
|
|||
*/
|
||||
public function run()
|
||||
{
|
||||
DB::table('formularies')->truncate();
|
||||
DB::table((new Formulary())->getTable())->truncate();
|
||||
$this->call(MandatoryFormularySeeder::class);
|
||||
Formulary::factory(14)->create();
|
||||
Formulary::factory(30)->create();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@ return [
|
|||
'settings' => 'Settings',
|
||||
'tags' => 'Tags',
|
||||
'formularies' => 'Formularies',
|
||||
'contacts' => 'Contacts',
|
||||
]
|
||||
];
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@ return [
|
|||
'settings' => 'Paramètres',
|
||||
'tags' => 'Étiquettes',
|
||||
'formularies' => 'Formulaires',
|
||||
'contacts' => 'Contacts',
|
||||
]
|
||||
];
|
||||
|
|
|
|||
1
resources/sass/bo/vendor/_bootstrap.scss
vendored
1
resources/sass/bo/vendor/_bootstrap.scss
vendored
|
|
@ -39,6 +39,7 @@
|
|||
@import "~bootstrap/scss/card";
|
||||
@import "~bootstrap/scss/breadcrumb";
|
||||
@import "~bootstrap/scss/progress";
|
||||
@import "~bootstrap/scss/accordion";
|
||||
|
||||
// 6. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss`
|
||||
@import "~bootstrap/scss/utilities/api";
|
||||
|
|
|
|||
|
|
@ -1,58 +1,51 @@
|
|||
@auth('backend')
|
||||
<ul class="navbar-nav me-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if(request()->routeIs('bo.dashboard')) active @endif"
|
||||
href="{{ route('bo.dashboard') }}"
|
||||
title="{{ __('Revenir au :model', ['model' => __('models.classes.dashboard')]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<a class="nav-link @if (request()->routeIs('bo.dashboard')) active @endif" data-bs-toggle="tooltip" href="{{ route('bo.dashboard') }}"
|
||||
title="{{ __('Revenir au :model', ['model' => __('models.classes.dashboard')]) }}">
|
||||
{{ __(':model', ['model' => __('models.classes.dashboard')]) }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if(request()->routeIs('bo.app-users.*')) active @endif"
|
||||
href="{{ route('bo.app-users.index') }}?rst=1"
|
||||
title="{{ __('Liste des :model', ['model' => __('models.classes.users')]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<a class="nav-link @if (request()->routeIs('bo.app-users.*')) active @endif" data-bs-toggle="tooltip"
|
||||
href="{{ route('bo.app-users.index') }}?rst=1" title="{{ __('Liste des :model', ['model' => __('models.classes.users')]) }}">
|
||||
{{ __(':model', ['model' => __('models.classes.users')]) }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if(request()->routeIs('bo.directories.*')) active @endif"
|
||||
href="{{ route('bo.directories.index') }}"
|
||||
title="{{ __('Liste des :model', ['model' => __('models.classes.directories')]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<a class="nav-link @if (request()->routeIs('bo.directories.*')) active @endif" data-bs-toggle="tooltip"
|
||||
href="{{ route('bo.directories.index') }}" title="{{ __('Liste des :model', ['model' => __('models.classes.directories')]) }}">
|
||||
{{ __(':model', ['model' => __('models.classes.directories')]) }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if(request()->routeIs('bo.documents.*')) active @endif"
|
||||
href="{{ route('bo.documents.index') }}"
|
||||
title="{{ __('Liste des :model', ['model' => __('models.classes.documents')]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<a class="nav-link @if (request()->routeIs('bo.documents.*')) active @endif" data-bs-toggle="tooltip"
|
||||
href="{{ route('bo.documents.index') }}" title="{{ __('Liste des :model', ['model' => __('models.classes.documents')]) }}">
|
||||
{{ __(':model', ['model' => __('models.classes.documents')]) }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if(request()->routeIs('bo.tags.*')) active @endif"
|
||||
href="{{ route('bo.tags.index') }}"
|
||||
title="{{ __('Liste des :model', ['model' => __('models.classes.tags')]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<a class="nav-link @if (request()->routeIs('bo.tags.*')) active @endif" data-bs-toggle="tooltip" href="{{ route('bo.tags.index') }}"
|
||||
title="{{ __('Liste des :model', ['model' => __('models.classes.tags')]) }}">
|
||||
{{ __(':model', ['model' => __('models.classes.tags')]) }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if(request()->routeIs('bo.formularies.*')) active @endif"
|
||||
<a class="nav-link @if (request()->routeIs('bo.formularies.*')) active @endif" data-bs-toggle="tooltip"
|
||||
href="{{ route('bo.formularies.index') }}"
|
||||
title="{{ __('Liste des champs du :model', ['model' => Str::singular(__('models.classes.formularies'))]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
title="{{ __('Liste des champs du :model', ['model' => Str::singular(__('models.classes.formularies'))]) }}">
|
||||
{{ __(':model', ['model' => Str::singular(__('models.classes.formularies'))]) }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if(request()->routeIs('bo.settings.*')) active @endif"
|
||||
href="{{ route('bo.settings.index') }}"
|
||||
title="{{ __('Liste des :model', ['model' => __('models.classes.settings')]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<a class="nav-link @if (request()->routeIs('bo.contacts.*')) active @endif" data-bs-toggle="tooltip"
|
||||
href="{{ route('bo.contacts.index') }}" title="{{ __('Liste des :model', ['model' => __('models.classes.contacts')]) }}">
|
||||
{{ __(':model', ['model' => __('models.classes.contacts')]) }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link @if (request()->routeIs('bo.settings.*')) active @endif" data-bs-toggle="tooltip"
|
||||
href="{{ route('bo.settings.index') }}" title="{{ __('Liste des :model', ['model' => __('models.classes.settings')]) }}">
|
||||
{{ __(':model', ['model' => __('models.classes.settings')]) }}
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
|||
70
resources/views/bo/pages/contacts/form.blade.php
Normal file
70
resources/views/bo/pages/contacts/form.blade.php
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<div class="row">
|
||||
{{-- TITLE --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Informations générales') }}</legend>
|
||||
@php
|
||||
$data = [
|
||||
'id' => 'document',
|
||||
'documents' => $documents,
|
||||
'directories' => $directories,
|
||||
'model' => $documentModel ?? null,
|
||||
'languages' => \App\Enums\Documents\LangEnum::toArray(),
|
||||
'csrf' => csrf_token(),
|
||||
];
|
||||
@endphp
|
||||
<div class="crud-document-input" data-json='@json($data)'></div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- TAGS --}}
|
||||
<div class="col-12 mb-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Étiquettes') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12 mb-3">
|
||||
@include('bo.partials.inputs.pivot-belongs-to-many', [
|
||||
'id' => 'app_userAuthorizedFolders',
|
||||
'name' => 'tags',
|
||||
'label' => __('Étiquettes associées'),
|
||||
'model' => $documentModel ?? null,
|
||||
'itemsList' => $tags,
|
||||
'itemLimit' => [0,5],
|
||||
'placeholder' => __('Recherchez une étiquette'),
|
||||
'helper' => __('Sélectionner des étiquettes parmis la liste (0 minimum et 5 maximum).'),
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
{{-- STATUS --}}
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<fieldset class="border h-100 bg-white p-3">
|
||||
<legend>{{ __('Publication') }}</legend>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
@include('bo.partials.inputs.boolean-switch', [
|
||||
'id' => 'documentStatus',
|
||||
'name' => 'status',
|
||||
'label' => __('État de publication'),
|
||||
'model' => $documentModel ?? null,
|
||||
'helper' => __('Le document est publié ou non.')
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
<script nonce="{{ $nonce }}">
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
// Submit button clone.
|
||||
const submit = document.getElementById('formSubmit')
|
||||
submitClone = document.getElementById('formSubmitClone');
|
||||
submitClone.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
submit.click('');
|
||||
})
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
56
resources/views/bo/pages/contacts/index-list.blade.php
Normal file
56
resources/views/bo/pages/contacts/index-list.blade.php
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<div class="table-responsive">
|
||||
<table class="fix-action table">
|
||||
<thead>
|
||||
@php
|
||||
$cols = [
|
||||
'email' => __('Email'),
|
||||
'phone' => __('Téléphone'),
|
||||
'lastname' => __('Nom'),
|
||||
'updated_at' => __('Mis à jour'),
|
||||
];
|
||||
@endphp
|
||||
@include('bo.modules.table-col-sorter', [
|
||||
'cols' => $cols,
|
||||
'mobileHide' => [],
|
||||
])
|
||||
</thead>
|
||||
<tbody>
|
||||
@if ($contactModelList->count())
|
||||
@foreach ($contactModelList as $contactModel)
|
||||
<tr>
|
||||
<td class="align-middle">
|
||||
<span>{{ $contactModel->email }}</span>
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<span>{{ $contactModel->phone }}</span>
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<span>{{ $contactModel->lastname }} {{ $contactModel->firsname }}</span>
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<span>{{ $contactModel->updated_at->isoFormat('\L\e DD/MM/YYYY \à HH:mm') }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-sm btn-warning" data-bs-toggle="tooltip"
|
||||
href="{{ route('bo.contacts.show', $contactModel) }}"
|
||||
title="{{ __('Visualiser le :model', ['model' => Str::singular(__('models.classes.contacts'))]) }}"
|
||||
role="button" target="blank">
|
||||
<i class="fa-solid fa-eye"></i>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@else
|
||||
<tr>
|
||||
<td class="text-center" colspan="{{ count($cols) + 1 }}">
|
||||
<span class="h3">
|
||||
{{ __('Aucun résultat pour les :models', ['models' => __('models.classes.documents')]) }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
36
resources/views/bo/pages/contacts/index.blade.php
Normal file
36
resources/views/bo/pages/contacts/index.blade.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
@extends('bo.layout')
|
||||
|
||||
@section('title', sprintf('%s - %s', __('models.classes.contacts'), Str::ucfirst(__('liste'))))
|
||||
@section('description', __('Page de contôle sur tous les contacts de l\'application.'))
|
||||
|
||||
@section('breadcrumb',
|
||||
request()->route()->getName())
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h1 class="col h2">
|
||||
<span class="fw-bold">{{ __('models.classes.contacts') }}</span> <small
|
||||
class="text-muted">{{ Str::ucfirst(__('liste')) }}</small>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="col d-flex justify-content-end align-items-center">
|
||||
<div class="justify-content-end ms-1">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@include('bo.modules.search-bar')
|
||||
<div class="row mt-3">
|
||||
<div class="col">
|
||||
@include('bo.pages.contacts.index-list')
|
||||
</div>
|
||||
</div>
|
||||
{{ $contactModelList->withQueryString()->onEachSide(1)->links() }}
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
138
resources/views/bo/pages/contacts/show.blade.php
Normal file
138
resources/views/bo/pages/contacts/show.blade.php
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
@extends('bo.layout')
|
||||
|
||||
@section('title', sprintf('%s - %s', __('models.classes.contacts'), Str::ucfirst(__('liste'))))
|
||||
@section('description', __('Page de contôle sur tous les contacts de l\'application.'))
|
||||
|
||||
@section('breadcrumb',
|
||||
request()->route()->getName())
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h1 class="text-md-start h2 text-center">
|
||||
<a class="btn btn-primary text-decoration-none m-0" data-bs="tooltip" data-bs-placement="top" data-bs-toggle="tooltip"
|
||||
href="{{ route('bo.contacts.index') }}"
|
||||
title="{{ __('Retourner sur la liste des :model', ['model' => __('models.classes.contacts')]) }}">
|
||||
<i class="fa-solid fa-arrow-left"></i>
|
||||
</a>
|
||||
<span class="fw-bold">{{ Str::singular(__('models.classes.contacts')) }}</span> <small
|
||||
class="text-muted">{{ Str::ucfirst(__('voir')) }}</small>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="col d-flex justify-content-end align-items-center">
|
||||
<div class="justify-content-end ms-1">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row mt-3">
|
||||
<div class="col">
|
||||
<div class="container">
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 d-flex flex-column flex-md-row justify-content-center" colspan="2">
|
||||
<span class="mx-3"><span class="fw-bold">{{ __('Crée le') }}</span>
|
||||
{{ $contactModel->created_at->isoFormat('DD/MM/YYYY \à HH:mm') }}</span>
|
||||
<span class="mx-3"><span class="fw-bold">{{ __('Mis à jour le') }}</span>
|
||||
{{ $contactModel->updated_at->isoFormat('DD/MM/YYYY \à HH:mm') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{-- EMAIL --}}
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-md-4 col-lg3"><span class="fw-bold">{{ __('Email') }}</span><span
|
||||
class="fw-bold"> ({{ __('obligatoire') }})</span></div>
|
||||
<div class="col align-middle">
|
||||
<pre class="h5 text-bg-light p-3">{{ $contactModel->email }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
{{-- LASTNAME --}}
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-md-4 col-lg3"><span class="fw-bold">{{ __('Nom') }}</span><span
|
||||
class="fw-bold"> ({{ __('obligatoire') }})</span></div>
|
||||
<div class="col align-middle">
|
||||
<pre class="text-bg-light p-3">{{ $contactModel->lastname }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
{{-- FIRSTNAME --}}
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-md-4 col-lg3"><span class="fw-bold">{{ __('Prénom') }}</span><span
|
||||
class="fw-bold"> ({{ __('obligatoire') }})</span></div>
|
||||
<div class="col align-middle">
|
||||
<pre class="text-bg-light p-3">{{ $contactModel->firstname }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
{{-- PHONE --}}
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-md-4 col-lg3"><span class="fw-bold">{{ __('Téléphone') }}</span><span
|
||||
class="fw-bold"> ({{ __('obligatoire') }})</span></div>
|
||||
<div class="col align-middle">
|
||||
<pre class="text-bg-light p-3">{{ $contactModel->phone }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
{{-- NOTES --}}
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 col-md-4 col-lg3"><span class="fw-bold">{{ __('Notes') }}</span></div>
|
||||
<div class="col align-middle">
|
||||
<pre class="text-bg-light p-3">{{ $contactModel->notes }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
{{-- VISITES --}}
|
||||
<div class="row mb-3">
|
||||
<div class="col-12"><span class="fw-bold">{{ __('Visites') }}</span></div>
|
||||
<div class="col align-middle">
|
||||
@if (collect($contactModel->visits)->filter()->count())
|
||||
<div class="accordion" id="visitesAccordion">
|
||||
@foreach ($contactModel->visits as $index => $visit)
|
||||
<div class="accordion-item">
|
||||
<div class="accordion-header">
|
||||
<button class="accordion-button collapsed" data-bs-toggle="collapse"
|
||||
data-bs-target="#collapse{{ $index }}" type="button" aria-expanded="false"
|
||||
aria-controls="collapse{{ $index }}">
|
||||
<span class="h5">{{ $visit['title'] }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="accordion-collapse collapse" id="collapse{{ $index }}"
|
||||
data-bs-parent="#visitesAccordion">
|
||||
<div class="accordion-body">
|
||||
<pre class="text-bg-light p-3">{{ $visit['note'] }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
<span class="fs-bold">{{ __('Aucune visite') }}</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
{{-- DATA --}}
|
||||
@if (count($contactModel->data))
|
||||
<div class="row mb-3">
|
||||
<div class="col-12"><span class="fw-bold">{{ __('Autres champs') }}</span></div>
|
||||
<div class="col align-middle">
|
||||
<div class="container">
|
||||
@foreach ($contactModel->data as $index => $input)
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-4 col-lg3"><span class="fw-bold">{{ $input->data->title }}</span>
|
||||
@if ($input->isRequired())
|
||||
<span class="fw-bold"> ({{ __('obligatoire') }})</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="col align-middle">
|
||||
<pre class="text-bg-light p-3">{{ collect($input->data->value)->filter()->implode(', ') }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -5,42 +5,33 @@
|
|||
@section('breadcrumb', 'no')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card text-center">
|
||||
<div class="card-header fw-bold">
|
||||
<h1 class="h2 fw-bold">{{ __('Dashboard') }}</h1>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">
|
||||
{{ __('Bonjour :firstname :lastname !', [
|
||||
'firstname' => Auth::user()->firstname,
|
||||
'lastname' => Auth::user()->lastname
|
||||
]) }}
|
||||
</h5>
|
||||
<p class="card-text m-0">
|
||||
{{ __('Bienvenue dans le back-office, où vous pouvez gérer votre application web.') }}
|
||||
</p>
|
||||
<p class="card-text">
|
||||
{{ __('Pour tout problème ou évolution souhaitée, veuillez nous contacter via notre outil : ') }}
|
||||
<a href="https://supportweb.ldc.fr" target="blank"
|
||||
title="{{ __('Accéder à notre outil de ticketing') }}"
|
||||
data-bs-toggle="tooltip">
|
||||
supportweb.ldc.fr
|
||||
</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a href="{{ route('bo.dashboard.export-contacts') }}"
|
||||
class="btn btn-primary"
|
||||
title="{{ __('Exportation de tous les contacts enregistrés dans un fichier .csv') }}"
|
||||
data-bs-toggle="tooltip">
|
||||
{{ __('Exporter les contacts') }}
|
||||
</a>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card text-center">
|
||||
<div class="card-header fw-bold">
|
||||
<h1 class="h2 fw-bold">{{ __('Dashboard') }}</h1>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">
|
||||
{{ __('Bonjour :firstname :lastname !', [
|
||||
'firstname' => Auth::user()->firstname,
|
||||
'lastname' => Auth::user()->lastname,
|
||||
]) }}
|
||||
</h5>
|
||||
<p class="card-text m-0">
|
||||
{{ __('Bienvenue dans le back-office, où vous pouvez gérer votre application web.') }}
|
||||
</p>
|
||||
<p class="card-text">
|
||||
{{ __('Pour tout problème ou évolution souhaitée, veuillez nous contacter via notre outil : ') }}
|
||||
<a data-bs-toggle="tooltip" href="https://supportweb.ldc.fr" title="{{ __('Accéder à notre outil de ticketing') }}"
|
||||
target="blank">
|
||||
supportweb.ldc.fr
|
||||
</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ Route::name('api.')->middleware('api.token')->group(function () {
|
|||
Route::get('directories', [SyncController::class, 'getDirectories'])->name('directories.index');
|
||||
Route::get('documents', [SyncController::class, 'getDocuments'])->name('documents.index');
|
||||
Route::get('version', [SyncController::class, 'getVersion'])->name('version');
|
||||
Route::post('contacts', [SyncController::class, 'getContacts'])->name('contacts.index');
|
||||
Route::get('contacts/{app_user}', [SyncController::class, 'getContacts'])->name('contacts.index');
|
||||
Route::post('contacts/{app_user}', [SyncController::class, 'upsertContact'])->name('contacts.upsert');
|
||||
Route::delete('contacts/{app_user}', [SyncController::class, 'destroyContacts'])->name('contacts.delete');
|
||||
Route::post('sendBrochure', [SyncController::class, 'SendFlyer'])->name('send-flyers');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use App\Http\Controllers\Bo\AppUserController;
|
||||
use App\Http\Controllers\Bo\ContactController;
|
||||
use App\Http\Controllers\Bo\FormularyController;
|
||||
use App\Http\Controllers\Bo\DashboardController;
|
||||
use App\Http\Controllers\Bo\DirectoriesController;
|
||||
|
|
@ -29,8 +30,8 @@ Route::prefix('bo')->name('bo.')->middleware(['admin-secure'])->group(function (
|
|||
Route::middleware('auth:backend')->group(function () {
|
||||
Route::get('/', [DashboardController::class, 'index'])->name('dashboard');
|
||||
|
||||
// * EXPORT CONTACT
|
||||
Route::get('/export-contact', [DashboardController::class, 'exportContact'])->name('dashboard.export-contacts');
|
||||
// * CONTACTS
|
||||
Route::resource('contacts', ContactController::class)->only(['index', 'show']);
|
||||
|
||||
// * APP_USERS
|
||||
Route::resource('app-users', AppUserController::class)->except('show');
|
||||
|
|
@ -41,7 +42,7 @@ Route::prefix('bo')->name('bo.')->middleware(['admin-secure'])->group(function (
|
|||
// * DIRECTORIES
|
||||
Route::resource('directories', DirectoriesController::class)->except('show');
|
||||
Route::post('/directories/save-order/{directories}', [DirectoriesController::class, 'saveOrder'])
|
||||
->name('directories.save-order');
|
||||
->name('directories.save-order');
|
||||
Route::post('/directories/need-authorization/{id}', [DirectoriesController::class, 'needAuthorization'])
|
||||
->name('directories.need-authorization');
|
||||
|
||||
|
|
@ -65,7 +66,7 @@ Route::prefix('bo')->name('bo.')->middleware(['admin-secure'])->group(function (
|
|||
// * FORMULARIES
|
||||
Route::resource('formularies', FormularyController::class)->except('show');
|
||||
Route::post('/formularies/{formulary}/change-order', [FormularyController::class, 'changeOrder'])
|
||||
->name('formularies.change-order');
|
||||
->name('formularies.change-order');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue