``🗑️ chore: Supprime les contrôleurs et templates obsolètes du newsletter
Ce commit supprime les fichiers obsolètes liés à la gestion des newsletters. Ces fichiers ne sont plus utilisés et leur suppression simplifie le code base. Les fichiers supprimés incluent des contrôleurs, des templates Twig et des classes JavaScript.
This commit is contained in:
1
.env
1
.env
@@ -72,3 +72,4 @@ AMAZON_SES_SECRET=BD63dADmgFJJPnjlT9utRDlvcOh8pRH3eOZXsyhNL/F3
|
||||
# MAILER_DSN=ses://ACCESS_KEY:SECRET_KEY@default?region=eu-west-1
|
||||
# MAILER_DSN=ses+smtp://ACCESS_KEY:SECRET_KEY@default?region=eu-west-1
|
||||
###< symfony/amazon-mailer ###
|
||||
CLOUDFLARE_TOKEN=4mqx9d7ynvoeCaXonJA07U19rH8gGhctqp7j2Lch
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -32,3 +32,4 @@ phpstan.neon
|
||||
coverage/
|
||||
.phpunit.cache
|
||||
/public/build
|
||||
script/demande/hosts.ini
|
||||
|
||||
@@ -4,8 +4,8 @@ import {AutoSubmit} from './class/AutoSubmit'
|
||||
import {ServerCard} from './class/ServerCard'
|
||||
import {AutoCustomer} from './class/AutoCustomer'
|
||||
import {RepeatLine} from './class/RepeatLine'
|
||||
import {RegisterPayment} from './class/RegisterPayment'
|
||||
import {OrderCtrl} from './class/OrderCtrl'
|
||||
import {MainframeEmailEditor} from './class/MainframeEmailEditor'
|
||||
import preactCustomElement from './functions/preact'
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ function script() {
|
||||
customElements.define('auto-customer',AutoCustomer,{extends:'button'})
|
||||
customElements.define('repeat-line',RepeatLine,{extends:'div'})
|
||||
customElements.define('order-ctrl',OrderCtrl,{extends:'div'})
|
||||
customElements.define("email-builder",MainframeEmailEditor)
|
||||
customElements.define("register-payment",RegisterPayment,{extends:'a'})
|
||||
}
|
||||
|
||||
function full() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
17
assets/class/RegisterPayment.js
Normal file
17
assets/class/RegisterPayment.js
Normal file
@@ -0,0 +1,17 @@
|
||||
export class RegisterPayment extends HTMLAnchorElement {
|
||||
connectedCallback() {
|
||||
let element = this;
|
||||
element.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
|
||||
let modal = document.createElement('div');
|
||||
modal.classList = "modal-payment"
|
||||
modal.innerHTML =`
|
||||
<div class="modal-payment-content">
|
||||
<h2>Enregistér un paiement</h2>
|
||||
</div>
|
||||
`;
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,11 @@
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-libxml": "*",
|
||||
"chillerlan/php-qrcode": "*",
|
||||
"cocur/slugify": "*",
|
||||
"doctrine/dbal": "^3.10",
|
||||
"doctrine/doctrine-bundle": "^2.15",
|
||||
"doctrine/doctrine-migrations-bundle": "^3.4.2",
|
||||
@@ -69,9 +72,7 @@
|
||||
"twig/extra-bundle": "^3.21",
|
||||
"twig/intl-extra": "^3.21",
|
||||
"twig/twig": "^3.21",
|
||||
"vich/uploader-bundle": "^2.7",
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*"
|
||||
"vich/uploader-bundle": "^2.7"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
|
||||
1704
composer.lock
generated
1704
composer.lock
generated
File diff suppressed because it is too large
Load Diff
32
migrations/Version20250924074745.php
Normal file
32
migrations/Version20250924074745.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20250924074745 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TABLE revendeur (id SERIAL NOT NULL, raison_social VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, surname VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, phone VARCHAR(255) NOT NULL, parent INT DEFAULT NULL, PRIMARY KEY(id))');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE SCHEMA public');
|
||||
$this->addSql('DROP TABLE revendeur');
|
||||
}
|
||||
}
|
||||
20
package.json
20
package.json
@@ -10,28 +10,28 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hotwired/stimulus": "^3.0.0",
|
||||
"@symfony/stimulus-bridge": "^3.2.0 || ^4.0.0",
|
||||
"@tailwindcss/postcss": "^4.1.10",
|
||||
"@hotwired/stimulus": "^3.2.2",
|
||||
"@symfony/stimulus-bridge": "^4.0.1",
|
||||
"@tailwindcss/postcss": "^4.1.13",
|
||||
"postcss": "^8.5.6",
|
||||
"postcss-scss": "^4.0.9",
|
||||
"rollup-plugin-javascript-obfuscator": "^1.0.4",
|
||||
"sass": "^1.89.2",
|
||||
"vite": "^7.0.0"
|
||||
"sass": "^1.93.0",
|
||||
"vite": "^7.1.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@grafikart/drop-files-element": "^1.0.9",
|
||||
"@grapesjs/studio-sdk": "^1.0.55",
|
||||
"@grapesjs/studio-sdk-plugins": "^1.0.27",
|
||||
"@grapesjs/studio-sdk": "^1.0.56",
|
||||
"@grapesjs/studio-sdk-plugins": "^1.0.28",
|
||||
"@hotwired/turbo": "^8.0.13",
|
||||
"@preact/preset-vite": "^2.10.2",
|
||||
"@sentry/browser": "^9.34.0",
|
||||
"@tailwindcss/vite": "^4.1.10",
|
||||
"@sentry/browser": "^9.46.0",
|
||||
"@tailwindcss/vite": "^4.1.13",
|
||||
"@usewaypoint/email-builder": "^0.0.8",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"body-scroll-lock": "^4.0.0-beta.0",
|
||||
"react-email-editor": "^1.7.11",
|
||||
"sortablejs": "^1.15.6",
|
||||
"tailwindcss": "^4.1.10"
|
||||
"tailwindcss": "^4.1.13"
|
||||
}
|
||||
}
|
||||
|
||||
14
script/demande/playbook.yaml
Normal file
14
script/demande/playbook.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
- hosts: all
|
||||
connection: local
|
||||
become: true
|
||||
tasks:
|
||||
- name: "Prepare hosts {{ path }}"
|
||||
ansible.builtin.debug:
|
||||
msg: "The path value is: {{ path }}"
|
||||
|
||||
- name: "Create template file"
|
||||
ansible.builtin.template:
|
||||
src: caddy.j2
|
||||
dest: "/etc/caddy/sites/{{ path }}.conf"
|
||||
mode: '0644'
|
||||
31
script/demande/templates/caddy.j2
Normal file
31
script/demande/templates/caddy.j2
Normal file
@@ -0,0 +1,31 @@
|
||||
{{ path }}.esy-web.fr {
|
||||
tls {
|
||||
dns cloudflare bnbe6SmF2kYBnDi4rEeoPI0wNXeFDWn0xZv7Dnfp;
|
||||
}
|
||||
root /var/www/mainframe/public
|
||||
file_server
|
||||
header {
|
||||
-Server
|
||||
Server "Esy-Web"
|
||||
-Via
|
||||
-X-Robots-Tag
|
||||
# Security headers
|
||||
X-Content-Type-Options "nosniff"
|
||||
X-XSS-Protection "0"
|
||||
Referrer-Policy "no-referrer"
|
||||
Permissions-Policy "geolocation=(), microphone=(), camera=()"
|
||||
}
|
||||
route {
|
||||
php_fastcgi unix//run/php/php8.3-fpm.sock {
|
||||
trusted_proxies private_ranges
|
||||
read_timeout 300s
|
||||
write_timeout 300s
|
||||
dial_timeout 100s
|
||||
env HTTP_PROXY ""
|
||||
}
|
||||
|
||||
request_body {
|
||||
max_size 100MB
|
||||
}
|
||||
}
|
||||
}
|
||||
44
src/Command/DemandeCommand.php
Normal file
44
src/Command/DemandeCommand.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\Revendeur;
|
||||
use App\Repository\RevendeurRepository;
|
||||
use App\Service\Revendeur\RevendeurService;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
#[AsCommand(name: 'mainframe:demande', description: 'Command generate for hosted file')]
|
||||
class DemandeCommand extends Command
|
||||
{
|
||||
|
||||
public function __construct(
|
||||
private readonly KernelInterface $kernelInterface,
|
||||
private readonly RevendeurService $revendeurService,
|
||||
?string $name = null)
|
||||
{
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$hosts =[];
|
||||
$hosts[] = "[local_hosts]";
|
||||
/** @var Revendeur $revendeur */
|
||||
foreach ($this->revendeurService->list() as $revendeur) {
|
||||
$hosts[] =$revendeur->getCode()."-demande ansible_host=127.0.0.1 path=".$revendeur->getCode()."-demande";
|
||||
}
|
||||
|
||||
$pathFile = $this->kernelInterface->getProjectDir()."/script/demande/hosts.ini";
|
||||
if(file_exists($pathFile)) {
|
||||
unlink($pathFile);
|
||||
}
|
||||
file_put_contents($pathFile, implode("\n", $hosts));
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Artemis\Newsletter;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class CompaignController extends AbstractController
|
||||
{
|
||||
#[Route(path: '/artemis/newsletter/campaign',name: 'artemis_newsletter_campaign',methods: ['GET', 'POST'])]
|
||||
public function artemis(): Response
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Artemis\Newsletter;
|
||||
|
||||
use App\Entity\Newsletter\Contact;
|
||||
use App\Entity\Newsletter\ContactLine;
|
||||
use App\Form\Artemis\Newsletter\ContactLineType;
|
||||
use App\Form\Artemis\Newsletter\ContactListType;
|
||||
use App\Repository\Newsletter\ContactRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
|
||||
class ContactController extends AbstractController
|
||||
{
|
||||
#[Route(path: '/artemis/newsletter/contact',name: 'artemis_newsletter_contact',methods: ['GET', 'POST'])]
|
||||
public function contacts(ContactRepository $contactRepository): Response
|
||||
{
|
||||
|
||||
$contacts = $contactRepository->findBy([],['id'=>'ASC']);
|
||||
|
||||
|
||||
// Affiche dans un template Twig (à créer)
|
||||
return $this->render('artemis/newsletter/contact.twig', [
|
||||
'lists' => $contacts,
|
||||
]);
|
||||
}
|
||||
#[Route(path: '/artemis/newsletter/contact/add', name: 'artemis_newsletter_contact_add', methods: ['GET', 'POST'])]
|
||||
public function contactsAdd(Request $request, EntityManagerInterface $em): Response
|
||||
{
|
||||
$contactList = new Contact();
|
||||
$form = $this->createForm(ContactListType::class, $contactList);
|
||||
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$contactList->setUuid(Uuid::v4());
|
||||
$em->persist($contactList);
|
||||
$em->flush();
|
||||
|
||||
$this->addFlash('success', 'La liste a été créée avec succès.');
|
||||
|
||||
// Redirige vers la liste des listes (à adapter selon ta route)
|
||||
return $this->redirectToRoute('artemis_newsletter_contact_edit',['id'=>$contactList->getId()]);
|
||||
}
|
||||
|
||||
return $this->render('artemis/newsletter/contact/add.twig', [
|
||||
'form' => $form->createView(),
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route(path: '/artemis/newsletter/contact/edit/{id}',name: 'artemis_newsletter_contact_edit',methods: ['GET', 'POST'])]
|
||||
public function contactsEdit(?Contact $contact,Request $request,EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
|
||||
if(!$contact instanceof Contact){
|
||||
return $this->redirectToRoute('artemis_newsletter_contact');
|
||||
}
|
||||
$form = $this->createForm(ContactListType::class, $contact);
|
||||
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$entityManager->persist($contact);
|
||||
$entityManager->flush();
|
||||
|
||||
$this->addFlash('success', 'La liste a été mise à jour');
|
||||
|
||||
// Redirige vers la liste des listes (à adapter selon ta route)
|
||||
return $this->redirectToRoute('artemis_newsletter_contact_edit',['id'=>$contact->getId()]);
|
||||
}
|
||||
if($request->files->has('contacts_file')) {
|
||||
$contacts_file = $request->files->get('contacts_file');
|
||||
$spreadsheet = IOFactory::load($contacts_file);
|
||||
// Récupérer la feuille active (première feuille)
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
// Lire la première ligne (en-têtes)
|
||||
$headerRow = $sheet->rangeToArray('A1:' . $sheet->getHighestColumn() . '1')[0];
|
||||
|
||||
// Normalisation : tout en minuscule, supprimer espaces avant/après
|
||||
$headerRowNormalized = array_map(function($header) {
|
||||
return mb_strtolower(trim((string) $header));
|
||||
}, $headerRow);
|
||||
|
||||
// Colonnes attendues (nom, prénom, email)
|
||||
$requiredColumns = ['nom','prenom', 'email'];
|
||||
|
||||
// Vérifier que chaque colonne attendue est bien présente dans l'en-tête
|
||||
$missingColumns = [];
|
||||
|
||||
foreach ($requiredColumns as $col) {
|
||||
// Pour "prénom" supporter aussi "prenom" (sans accent)
|
||||
if (!in_array($col, $headerRowNormalized, true)) {
|
||||
$missingColumns[] = $col;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($missingColumns) > 0) {
|
||||
// Colonnes manquantes : gérer l'erreur (throw, flash message, etc.)
|
||||
$missingStr = implode(', ', $missingColumns);
|
||||
$this->addFlash("error_import","Le fichier importé ne contient pas les colonnes obligatoires $missingStr");
|
||||
return $this->redirectToRoute('artemis_newsletter_contact_edit',['id'=>$contact->getId()]);
|
||||
}
|
||||
|
||||
$indexNom = array_search('nom', $headerRowNormalized, true);
|
||||
$indexPrenom = array_search('prenom', $headerRowNormalized, true);
|
||||
$indexEmail = array_search('email', $headerRowNormalized, true);
|
||||
|
||||
$contacts = 0;
|
||||
// Parcourir les lignes à partir de la 2e (données)
|
||||
$highestRow = $sheet->getHighestRow();
|
||||
for ($row = 2; $row <= $highestRow; $row++) {
|
||||
$rowData = $sheet->rangeToArray("A{$row}:" . $sheet->getHighestColumn() . $row)[0];
|
||||
|
||||
$nom = isset($rowData[$indexNom]) ? trim($rowData[$indexNom]) : null;
|
||||
$prenom = isset($rowData[$indexPrenom]) ? trim($rowData[$indexPrenom]) : null;
|
||||
$email = isset($rowData[$indexEmail]) ? trim($rowData[$indexEmail]) : null;
|
||||
|
||||
// Optionnel : valider email
|
||||
if ($email && filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$contactExist = $entityManager->getRepository(ContactLine::class)->findOneBy(['list'=>$contact,'email'=>$email]);
|
||||
if(!$contactExist instanceof ContactLine) {
|
||||
$contactLine = new ContactLine();
|
||||
$contactLine->setName($nom);
|
||||
$contactLine->setEmail($email);
|
||||
$contactLine->setSurname($prenom);
|
||||
$contactLine->setUuid(Uuid::v4());
|
||||
$entityManager->persist($contactLine);
|
||||
$contact->addContactLine($contactLine);
|
||||
$entityManager->persist($contact);
|
||||
$contacts++;
|
||||
}
|
||||
}
|
||||
$entityManager->flush();;
|
||||
}
|
||||
$this->addFlash('success', $contacts . ' contacts importés correctement.');
|
||||
return $this->redirectToRoute('artemis_newsletter_contact_edit',['id'=>$contact->getId()]);
|
||||
|
||||
}
|
||||
if($request->query->has('delete')) {
|
||||
foreach ($contact->getContactLines() as $contactLine) {
|
||||
$entityManager->remove($contactLine);
|
||||
}
|
||||
$entityManager->remove($contact);
|
||||
$entityManager->flush();
|
||||
$this->addFlash("success","Suppression effectuée");
|
||||
return $this->redirectToRoute('artemis_newsletter_contact');
|
||||
}
|
||||
if($request->query->has('export')) {
|
||||
$contactList =[
|
||||
['nom','surname','email']
|
||||
];
|
||||
foreach ($contact->getContactLines() as $contactLine) {
|
||||
$contactList[] = [$contactLine->getName(),$contactLine->getSurname(),$contactLine->getEmail()];
|
||||
}
|
||||
// Génération du CSV en mémoire
|
||||
$handle = fopen('php://memory', 'r+');
|
||||
foreach ($contactList as $row) {
|
||||
fputcsv($handle, $row, ';'); // point-virgule comme séparateur, à adapter si besoin
|
||||
}
|
||||
rewind($handle);
|
||||
$csvContent = stream_get_contents($handle);
|
||||
fclose($handle);
|
||||
|
||||
// Création de la réponse HTTP avec le CSV
|
||||
$response = new Response($csvContent);
|
||||
$response->headers->set('Content-Type', 'text/csv; charset=utf-8');
|
||||
// fichier téléchargé nommé contacts.csv
|
||||
$response->headers->set('Content-Disposition', 'attachment; filename="'.$contact->getName().'.csv"');
|
||||
|
||||
return $response;
|
||||
}
|
||||
if($request->query->has('deleteContact')) {
|
||||
$c = $entityManager->getRepository(ContactLine::class)->find($request->query->get('deleteContact'));
|
||||
if($c instanceof ContactLine) {
|
||||
$entityManager->remove($c);
|
||||
$entityManager->flush();
|
||||
}
|
||||
$this->addFlash("success","Suppression effectuée");
|
||||
return $this->redirectToRoute('artemis_newsletter_contact_edit',['id'=>$contact->getId()]);
|
||||
}
|
||||
|
||||
$contactLine = new ContactLine();
|
||||
$contactLine->setList($contact);
|
||||
$contactLine->setUuid(Uuid::v4());
|
||||
$formContact= $this->createForm(ContactLineType::class,$contactLine);
|
||||
$formContact->handleRequest($request);
|
||||
if ($formContact->isSubmitted() && $formContact->isValid()) {
|
||||
$entityManager->persist($contactLine);
|
||||
$entityManager->flush();
|
||||
$this->addFlash("success","Création effectuée");
|
||||
return $this->redirectToRoute('artemis_newsletter_contact_edit',['id'=>$contact->getId()]);
|
||||
}
|
||||
|
||||
//import
|
||||
return $this->render('artemis/newsletter/contact/edit.twig', [
|
||||
'form' => $form->createView(),
|
||||
'formContact' => $formContact->createView(),
|
||||
'contact' => $contact,
|
||||
]);
|
||||
}
|
||||
#[Route(path: '/artemis/newsletter/contact/delete',name: 'artemis_newsletter_contact_delete',methods: ['GET', 'POST'])]
|
||||
public function contactsDelete(?Contact $contact): Response
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Artemis\Newsletter;
|
||||
|
||||
use App\Entity\Newsletter\Template;
|
||||
use App\Form\Artemis\Newsletter\TemplateType;
|
||||
use App\Repository\Newsletter\TemplateRepository;
|
||||
use App\Service\Mailer\AmazonSesClient;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Exception;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class TemplateController extends AbstractController
|
||||
{
|
||||
#[Route(path: '/artemis/newsletter/template',name: 'artemis_newsletter_template',methods: ['GET', 'POST'])]
|
||||
public function templates(TemplateRepository $templateRepository): Response
|
||||
{
|
||||
$templates = $templateRepository->findBy([],['id'=>'ASC']);
|
||||
|
||||
|
||||
// Affiche dans un template Twig (à créer)
|
||||
return $this->render('artemis/newsletter/template.twig', [
|
||||
'templates' => $templates,
|
||||
]);
|
||||
|
||||
//load template listing
|
||||
//create editor for created template
|
||||
//header
|
||||
//content modify only campain
|
||||
//footer
|
||||
|
||||
//header sortable js
|
||||
//footer sortabke js
|
||||
|
||||
//1 col 2 col 3col
|
||||
//texte image network
|
||||
//button link
|
||||
|
||||
}
|
||||
|
||||
#[Route(path: '/artemis/newsletter/template/add',name: 'artemis_newsletter_template_add',methods: ['GET', 'POST'])]
|
||||
#[Route(path: '/artemis/newsletter/template/{id}',name: 'artemis_newsletter_template_edit',methods: ['GET', 'POST'])]
|
||||
public function templateEditor(?Template $template,AmazonSesClient $amazonSesClient,EntityManagerInterface $entityManager,Request $request): Response
|
||||
{
|
||||
if(is_null($template)){
|
||||
$template = new Template();
|
||||
}
|
||||
|
||||
|
||||
$form = $this->createForm(TemplateType::class,$template);
|
||||
$form->handleRequest($request);
|
||||
if($form->isSubmitted() && $form->isValid()){
|
||||
$entityManager->persist($template);
|
||||
$entityManager->flush();
|
||||
$this->addFlash("success","Mise à jour effectuée");
|
||||
return $this->redirectToRoute('artemis_newsletter_template_edit',['id'=>$template->getId()]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return $this->render('artemis/newsletter/template/editor.twig', [
|
||||
'form' => $form->createView(),
|
||||
'template' => $template,
|
||||
]);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#[Route(path: '/artemis/newsletter/template/{id}/preview',name: 'artemis_newsletter_template_preview',methods: ['GET', 'POST'])]
|
||||
public function templatePreview(?Template $template): Response
|
||||
{
|
||||
$configs = json_decode($template->getContent(),true);
|
||||
$mjml= $this->render('mails/preview.twig', [
|
||||
'cg' => $configs,
|
||||
]);
|
||||
|
||||
$html = $this->convertMjmlToHtml($mjml);
|
||||
return new Response($html);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private function convertMjmlToHtml(string $mjmlContent): string
|
||||
{
|
||||
$command = ['mjml', '--stdin'];
|
||||
$process = new Process($command);
|
||||
|
||||
try {
|
||||
$process->setInput($mjmlContent);
|
||||
$process->run();
|
||||
|
||||
// Exécute la commande et vérifie la réussite
|
||||
if (!$process->isSuccessful()) {
|
||||
throw new ProcessFailedException($process);
|
||||
}
|
||||
|
||||
return $process->getOutput();
|
||||
} catch (ProcessFailedException $exception) {
|
||||
return ''; // Retourne une chaîne vide en cas d'échec
|
||||
} catch (Exception $e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
40
src/Controller/Artemis/Revendeur/RevendeurController.php
Normal file
40
src/Controller/Artemis/Revendeur/RevendeurController.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Artemis\Revendeur;
|
||||
|
||||
use App\Entity\Revendeur;
|
||||
use App\Form\Artemis\Revendeur\RevendeurType;
|
||||
use App\Service\Revendeur\RevendeurService;
|
||||
use Cocur\Slugify\Slugify;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class RevendeurController extends AbstractController
|
||||
{
|
||||
#[Route(path: '/artemis/revendeur',name: 'artemis_revendeur')]
|
||||
public function revendeur(Request $request,RevendeurService $revendeurService): Response
|
||||
{
|
||||
|
||||
return $this->render('artemis/revendeur/revendeur.twig', [
|
||||
'revendeurLists' => $revendeurService->list(),
|
||||
]);
|
||||
|
||||
}
|
||||
#[Route(path: '/artemis/revendeur/add',name: 'artemis_revendeur_add')]
|
||||
public function revendeurAdd(Request $request,RevendeurService $revendeurService): Response
|
||||
{
|
||||
$r = new Revendeur();
|
||||
$form = $this->createForm(RevendeurType::class,$r);
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$slugify = new Slugify();
|
||||
$r->setCode($slugify->slugify($r->getRaisonSocial()));
|
||||
$revendeurService->create($r);
|
||||
}
|
||||
return $this->render('artemis/revendeur/revendeur_add.twig', [
|
||||
'form' => $form->createView(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
125
src/Entity/Revendeur.php
Normal file
125
src/Entity/Revendeur.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\RevendeurRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: RevendeurRepository::class)]
|
||||
class Revendeur
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $raisonSocial = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $code = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $name = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $surname = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $email = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $phone = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $parent = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getRaisonSocial(): ?string
|
||||
{
|
||||
return $this->raisonSocial;
|
||||
}
|
||||
|
||||
public function setRaisonSocial(string $raisonSocial): static
|
||||
{
|
||||
$this->raisonSocial = $raisonSocial;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCode(): ?string
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
public function setCode(string $code): static
|
||||
{
|
||||
$this->code = $code;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(string $name): static
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSurname(): ?string
|
||||
{
|
||||
return $this->surname;
|
||||
}
|
||||
|
||||
public function setSurname(string $surname): static
|
||||
{
|
||||
$this->surname = $surname;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEmail(): ?string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function setEmail(string $email): static
|
||||
{
|
||||
$this->email = $email;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPhone(): ?string
|
||||
{
|
||||
return $this->phone;
|
||||
}
|
||||
|
||||
public function setPhone(string $phone): static
|
||||
{
|
||||
$this->phone = $phone;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getParent(): ?int
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
public function setParent(?int $parent): static
|
||||
{
|
||||
$this->parent = $parent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
58
src/Form/Artemis/Revendeur/RevendeurType.php
Normal file
58
src/Form/Artemis/Revendeur/RevendeurType.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Form\Artemis\Revendeur;
|
||||
|
||||
use App\Entity\Customer;
|
||||
use App\Entity\Revendeur;
|
||||
use App\Service\Revendeur\RevendeurService;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class RevendeurType extends AbstractType
|
||||
{
|
||||
public function __construct(private RevendeurService $revendeurService)
|
||||
{
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$choices = [];
|
||||
foreach ($this->revendeurService->list() as $revendeur) {
|
||||
$choices[$revendeur->getId()] = $revendeur->getRaisonSocial();
|
||||
}
|
||||
$builder->add('raisonSocial',TextType::class,[
|
||||
'label' => 'Raison Sociale',
|
||||
'required' => true,
|
||||
])
|
||||
->add('name',TextType::class,[
|
||||
'label' => 'Nom',
|
||||
'required' => true,
|
||||
])
|
||||
->add('surname',TextType::class,[
|
||||
'label' => 'Prenom',
|
||||
'required' => true,
|
||||
])
|
||||
->add('email',EmailType::class,[
|
||||
'label' => 'Email',
|
||||
'required' => true,
|
||||
])
|
||||
->add('phone',TextType::class,[
|
||||
'label' => 'Telephone',
|
||||
'required' => true,
|
||||
])
|
||||
->add('parent',ChoiceType::class,[
|
||||
'label' => 'Revendeur Principal',
|
||||
'choices' => $choices,
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
}
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefault('data_class',Revendeur::class);
|
||||
}
|
||||
}
|
||||
43
src/Repository/RevendeurRepository.php
Normal file
43
src/Repository/RevendeurRepository.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Revendeur;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Revendeur>
|
||||
*/
|
||||
class RevendeurRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Revendeur::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return Revendeur[] Returns an array of Revendeur objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('r')
|
||||
// ->andWhere('r.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('r.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?Revendeur
|
||||
// {
|
||||
// return $this->createQueryBuilder('r')
|
||||
// ->andWhere('r.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
||||
52
src/Service/Revendeur/RevendeurService.php
Normal file
52
src/Service/Revendeur/RevendeurService.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service\Revendeur;
|
||||
|
||||
use App\Repository\RevendeurRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
class RevendeurService
|
||||
{
|
||||
public function __construct(
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly RevendeurRepository $revendeurRepository,
|
||||
private readonly HttpClientInterface $httpClient
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public function list(): array
|
||||
{
|
||||
$lists = [];
|
||||
foreach ($this->revendeurRepository->findAll() as $list) {
|
||||
$list->dns = $list->getCode() . "-demande.esy-web.fr";
|
||||
$lists[] = $list;
|
||||
}
|
||||
return $lists;
|
||||
}
|
||||
|
||||
public function create(\App\Entity\Revendeur $r)
|
||||
{
|
||||
$this->entityManager->persist($r);
|
||||
$this->entityManager->flush();
|
||||
$dns = $r->getCode() . "-demande.esy-web.fr";
|
||||
$ZONE_ID = "7b8ae9e2a488d574b19dfa72a67326d9";
|
||||
$this->httpClient->request('POST', 'https://api.cloudflare.com/client/v4/zones/' . $ZONE_ID . '/dns_records', [
|
||||
"headers" => [
|
||||
'Content-Type' => 'application/json',
|
||||
'Authorization' => 'Bearer ' . $_ENV['CLOUDFLARE_TOKEN'],
|
||||
],
|
||||
'json' => [
|
||||
'name' => $dns,
|
||||
'ttl' => 1,
|
||||
'type' => 'A',
|
||||
'comment' => 'Link for ' . $r->getRaisonSocial() . " for created",
|
||||
'content' => '35.204.191.160',
|
||||
'proxied' => true,
|
||||
]
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -81,33 +81,6 @@
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="px-4 py-2">
|
||||
<button class="flex items-center justify-between w-full p-2 text-base font-normal text-gray-900 dark:text-white rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none" data-submenu-toggle="newsletter">
|
||||
<div class="flex items-center">
|
||||
<svg class="w-6 h-6 text-gray-500 dark:text-gray-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 10a8 8 0 018-8v8h8a8 8 0 11-16 0z"></path>
|
||||
<path d="M12 2.252A8.014 8.014 0 0117.748 12H12V2.252z"></path>
|
||||
</svg>
|
||||
<span class="ml-3">Newsletter</span>
|
||||
</div>
|
||||
<svg class="w-4 h-4 text-gray-500 dark:text-gray-400 arrow-icon" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<ul id="submenu-newsletter" class="submenu ml-6 mt-2 space-y-2">
|
||||
<li>
|
||||
<a href="{{ path('artemis_newsletter_contact') }}" class="flex items-center p-2 text-base font-normal text-gray-900 dark:text-white {% if app.request.get('_route') == 'artemis_newsletter_contact' %}bg-gray-200 dark:bg-gray-700{% endif %} rounded-lg">
|
||||
<span class="ml-3">Liste de contact</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ path('artemis_newsletter_template') }}" class="flex items-center p-2 text-base font-normal text-gray-900 dark:text-white {% if app.request.get('_route') == 'artemis_newsletter_contact' %}bg-gray-200 dark:bg-gray-700{% endif %} rounded-lg">
|
||||
<span class="ml-3">Liste de template</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
<li class="px-4 py-2">
|
||||
<button class="flex items-center justify-between w-full p-2 text-base font-normal text-gray-900 dark:text-white rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none" data-submenu-toggle="intranet">
|
||||
<div class="flex items-center">
|
||||
@@ -130,7 +103,22 @@
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="px-4 py-2">
|
||||
<button class="flex items-center justify-between w-full p-2 text-base font-normal text-gray-900 dark:text-white rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none" data-submenu-toggle="revendeur">
|
||||
<div class="flex items-center">
|
||||
<svg class="w-6 h-6 text-gray-500 dark:text-gray-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 10a8 8 0 018-8v8h8a8 8 0 11-16 0z"></path><path d="M12 2.252A8.014 8.014 0 0117.748 12H12V2.252z"></path></svg>
|
||||
<span class="ml-3">Revendeur</span>
|
||||
</div>
|
||||
<svg class="w-4 h-4 text-gray-500 dark:text-gray-400 arrow-icon" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path></svg>
|
||||
</button>
|
||||
<ul id="submenu-revendeur" class="submenu ml-6 mt-2 space-y-2">
|
||||
<li>
|
||||
<a href="{{ path('artemis_revendeur') }}" class="flex items-center p-2 text-sm font-normal text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700">
|
||||
<span class="ml-3">Revendeur</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
{% if is_granted('ROLE_ADMIN') %}
|
||||
<li class="px-4 py-2">
|
||||
<button class="flex items-center justify-between w-full p-2 text-base font-normal text-gray-900 dark:text-white rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none" data-submenu-toggle="settings">
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
{% if orderAdvert.state == "pay" and orderAdvert.customerOrder is null %}
|
||||
<a href="{{ path('artemis_intranet_customer_view',{id:customer.id,current:'order',idAvis:orderAdvert.id,act:'createFacture'}) }}" class="block bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded">Crée la facture</a>
|
||||
{% endif %}
|
||||
{% if orderAdvert.state == "wait-bank" or orderAdvert.state == "wait-virement" %}
|
||||
<button is="register-payment" id="{{ orderAdvert.id }}" class="block bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded">Enregistrée un paiement</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
{% endif %}
|
||||
{% if orderOrder.state == "f-send" %}
|
||||
<a href="{{ path('artemis_intranet_customer_view',{id:customer.id,current:'order',idFacture:orderOrder.id,act:'resend'}) }}" class="block bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded">Réenvoyée la facture</a>
|
||||
{% endif %}}
|
||||
{% endif %}
|
||||
<a href="{{ vich_uploader_asset(orderOrder,'facture') }}" download="facture-{{ orderOrder.numOrder }}.pdf" class="block w-full mt-1 bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded">Télécharger la facture</a>
|
||||
|
||||
</td>
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
{% extends 'artemis/base.twig' %}
|
||||
|
||||
{% block title %}Listes de contacts{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h2 class="text-3xl font-semibold text-gray-800 dark:text-gray-200">Listes de contacts</h2>
|
||||
<div>
|
||||
<a href="{{ path('artemis_newsletter_contact_add') }}" class="px-4 py-2 bg-blue-600 text-white font-medium rounded-md shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900">
|
||||
+ Crée une liste de contact
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
|
||||
{% for list in lists %}
|
||||
<a href="{{ path('artemis_newsletter_contact_edit',{id:list.id}) }}" class="card-contact mt-6">
|
||||
<div class="card-body flex items-center">
|
||||
|
||||
<div class="px-3 py-2 rounded bg-indigo-600 text-white mr-3">
|
||||
<i class="fad fa-user"></i>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<h1 class="font-semibold">{{ list.name }}</h1>
|
||||
<p class="text-xs"><span class="num-2">{{ list.contactLines.count }}</span> Contact</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
{% else %}
|
||||
<div class="col-span-4 text-center text-gray-400 dark:text-gray-500 font-bold">Aucune liste trouvée.</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,22 +0,0 @@
|
||||
{% extends 'artemis/base.twig' %}
|
||||
|
||||
{% block title %}Créer une nouvelle liste{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="text-2xl font-semibold mb-6">Créer une nouvelle liste de contacts</h1>
|
||||
|
||||
<div class="bg-gray-800 rounded-lg shadow p-6 mb-6">
|
||||
{{ form_start(form, {'attr': {'class': 'max-w-md'}}) }}
|
||||
<div class="mb-4">
|
||||
{{ form_label(form.name, null, {'label_attr': {'class': 'block mb-1 font-medium text-gray-700 dark:text-gray-300'}}) }}
|
||||
{{ form_widget(form.name, {'attr': {
|
||||
'class': 'w-full p-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white'
|
||||
}}) }}
|
||||
{{ form_errors(form.name) }}
|
||||
</div>
|
||||
<button type="submit" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded transition font-semibold">
|
||||
Créer la liste
|
||||
</button>
|
||||
{{ form_end(form) }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,138 +0,0 @@
|
||||
{% extends 'artemis/base.twig' %}
|
||||
|
||||
{% block title %}Liste - {{ contact.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h1 class="text-2xl font-semibold mb-6">Liste - {{ contact.name }}</h1>
|
||||
<div>
|
||||
<a download="liste-{{ contact.name }}.csv" href="{{ path('artemis_newsletter_contact_edit',{id:contact.id,export:1}) }}" class="px-4 py-2 bg-blue-600 text-white font-medium rounded-md shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900">
|
||||
Exporter la liste des contact
|
||||
</a>
|
||||
<a href="{{ path('artemis_newsletter_contact_edit',{id:contact.id,delete :1}) }}" class="ml-2 px-4 py-2 bg-red-600 text-white font-medium rounded-md shadow-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900">
|
||||
Supprimer la liste des contact
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-800 rounded-lg shadow p-6 mb-6">
|
||||
{{ form_start(form, {'attr': {'class': 'w-full'}}) }}
|
||||
<div class="mb-4">
|
||||
{{ form_label(form.name, null, {'label_attr': {'class': 'block mb-1 font-medium text-gray-700 dark:text-gray-300'}}) }}
|
||||
{{ form_widget(form.name, {'attr': {
|
||||
'class': 'w-full p-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white'
|
||||
}}) }}
|
||||
{{ form_errors(form.name) }}
|
||||
</div>
|
||||
<button type="submit" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded transition font-semibold w-full">
|
||||
Modifié liste
|
||||
</button>
|
||||
{{ form_end(form) }}
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-800 rounded-lg shadow p-6 mb-6 flex flex-col items-center justify-center text-center border border-dashed border-blue-400">
|
||||
<div class="mb-4">
|
||||
<svg class="w-12 h-12 mx-auto text-blue-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 48 48">
|
||||
<rect x="8" y="18" width="32" height="22" rx="3" fill="currentColor" class="text-blue-100"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M24 6v22m0 0l-7-7m7 7l7-7" stroke="currentColor"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="text-lg font-semibold text-gray-100 mb-2">Importer des contacts</h2>
|
||||
<p class="text-gray-400 mb-4 text-sm">
|
||||
Téléversez un fichier <span class="font-semibold text-blue-300">CSV</span> ou <span class="font-semibold text-blue-300">Excel</span> pour ajouter plusieurs contacts à cette liste.<br>
|
||||
<span class="text-xs text-gray-500">Le fichier doit contenir les colonnes: email, nom, prénom…</span>
|
||||
</p>
|
||||
<form method="post" enctype="multipart/form-data" action="{{ path('artemis_newsletter_contact_edit', {'id': contact.id}) }}" class="flex flex-col items-center gap-4 w-full">
|
||||
<input
|
||||
type="file"
|
||||
name="contacts_file"
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
|
||||
class="block file:mr-4 file:px-4 file:py-2 text-gray-900 dark:text-gray-100
|
||||
file:rounded file:border-0 file:text-sm file:bg-blue-50 file:text-blue-700
|
||||
hover:file:bg-blue-100 focus:file:outline-none
|
||||
dark:file:bg-gray-700 dark:file:text-blue-300 dark:hover:file:bg-gray-600"
|
||||
required
|
||||
>
|
||||
<button type="submit" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded font-semibold transition w-full max-w-xs">
|
||||
Importer
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-800 rounded-lg shadow p-6 mb-6">
|
||||
<h3>Ajouter un contact</h3>
|
||||
{{ form_start(formContact, {'attr': {'class': 'w-full'}}) }}
|
||||
<div class="grid grid-cols-3">
|
||||
<div class="m-2">
|
||||
{{ form_label(formContact.name, null, {'label_attr': {'class': 'block mb-1 font-medium text-gray-700 dark:text-gray-300'}}) }}
|
||||
{{ form_widget(formContact.name, {'attr': {
|
||||
'class': 'w-full p-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white'
|
||||
}}) }}
|
||||
{{ form_errors(formContact.name) }}
|
||||
</div>
|
||||
<div class="m-2">
|
||||
{{ form_label(formContact.surname, null, {'label_attr': {'class': 'block mb-1 font-medium text-gray-700 dark:text-gray-300'}}) }}
|
||||
{{ form_widget(formContact.surname, {'attr': {
|
||||
'class': 'w-full p-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white'
|
||||
}}) }}
|
||||
{{ form_errors(formContact.surname) }}
|
||||
</div>
|
||||
<div class="m-2">
|
||||
{{ form_label(formContact.email, null, {'label_attr': {'class': 'block mb-1 font-medium text-gray-700 dark:text-gray-300'}}) }}
|
||||
{{ form_widget(formContact.email, {'attr': {
|
||||
'class': 'w-full p-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white'
|
||||
}}) }}
|
||||
{{ form_errors(formContact.email) }}
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded transition font-semibold w-full">
|
||||
Crée le contact
|
||||
</button>
|
||||
{{ form_end(formContact) }}
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-800 rounded-lg shadow mt-2">
|
||||
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
|
||||
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-3">
|
||||
Email
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3">
|
||||
Nom
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3">
|
||||
Prénom
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3">
|
||||
Status
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-3">
|
||||
Actions
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for line in contact.contactLines %}
|
||||
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700 border-gray-200">
|
||||
<th scope="row" class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white">
|
||||
{{ line.email }}
|
||||
</th>
|
||||
<td class="px-6 py-4">
|
||||
{{ line.name }}
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
{{ line.surname }}
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<i class="fad fa-check-circle text-green-500"></i>
|
||||
</td>
|
||||
<td class="px-6 py-4">
|
||||
<a class="button bg-red-900 text-white p-2" href="{{ app.request.pathInfo }}?deleteContact={{ line.id }}">Supprimer</a>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,34 +0,0 @@
|
||||
{% extends 'artemis/base.twig' %}
|
||||
|
||||
{% block title %}Listes de contacts{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h2 class="text-3xl font-semibold text-gray-800 dark:text-gray-200">Listes des templates</h2>
|
||||
<div>
|
||||
<a href="{{ path('artemis_newsletter_contact_add') }}" class="px-4 py-2 bg-blue-600 text-white font-medium rounded-md shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900">
|
||||
+ Crée un templates
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
|
||||
{% for template in templates %}
|
||||
<a href="" class="card-contact mt-6">
|
||||
<div class="card-body flex items-center">
|
||||
|
||||
<div class="px-3 py-2 rounded bg-indigo-600 text-white mr-3">
|
||||
<i class="fad fa-user"></i>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<h1 class="font-semibold">{{ template.name }}</h1>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{% else %}
|
||||
<div class="col-span-4 text-center text-gray-400 dark:text-gray-500 font-bold">Aucun template trouvée.</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,46 +0,0 @@
|
||||
{% extends 'artemis/base.twig' %}
|
||||
{% block title %}Template - {{ template.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h1 class="text-2xl font-semibold mb-6">Template - {{ template.name }}</h1>
|
||||
{% if template.id is not null %}
|
||||
<div>
|
||||
|
||||
<a target="_blank" href="{{ path('artemis_newsletter_template_preview',{id:template.id}) }}" class="ml-2 px-4 py-2 bg-blue-600 text-white font-medium rounded-md shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900">
|
||||
Voir le rendu
|
||||
</a>
|
||||
|
||||
<a href="{{ path('artemis_newsletter_template_edit',{id:template.id,delete :1}) }}" class="ml-2 px-4 py-2 bg-red-600 text-white font-medium rounded-md shadow-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900">
|
||||
Supprimer le template
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="bg-gray-800 rounded-lg shadow p-6 mb-6">
|
||||
{{ form_start(form, {'attr': {'class': 'w-full'}}) }}
|
||||
<div class="mb-4">
|
||||
{{ form_label(form.name, null, {'label_attr': {'class': 'block mb-1 font-medium text-gray-700 dark:text-gray-300'}}) }}
|
||||
{{ form_widget(form.name, {'attr': {
|
||||
'class': 'w-full p-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white'
|
||||
}}) }}
|
||||
{{ form_errors(form.name) }}
|
||||
</div>
|
||||
<button type="submit" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded transition font-semibold w-full">
|
||||
Sauvegarder
|
||||
</button>
|
||||
{{ form_end(form) }}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<email-builder id="{{ template.id }}"></email-builder>
|
||||
|
||||
//content management
|
||||
// left zone
|
||||
// central editor
|
||||
// right module
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
12
templates/artemis/revendeur/revendeur.twig
Normal file
12
templates/artemis/revendeur/revendeur.twig
Normal file
@@ -0,0 +1,12 @@
|
||||
{% extends 'artemis/base.twig' %}
|
||||
{% block title %}Revendeur(s){% endblock %}
|
||||
{% block content %}
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h2 class="text-3xl font-semibold text-gray-800 dark:text-gray-200">Listes des revendeur</h2>
|
||||
<div>
|
||||
<a href="{{ path('artemis_revendeur_add') }}" class="px-4 py-2 bg-blue-600 text-white font-medium rounded-md shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-900">
|
||||
+ Crée un revendeur
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
37
templates/artemis/revendeur/revendeur_add.twig
Normal file
37
templates/artemis/revendeur/revendeur_add.twig
Normal file
@@ -0,0 +1,37 @@
|
||||
{% extends 'artemis/base.twig' %}
|
||||
{% block title %}Crée un Revendeur(s){% endblock %}
|
||||
{% block content %}
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h2 class="text-3xl font-semibold text-gray-800 dark:text-gray-200">Crée un Revendeur</h2>
|
||||
|
||||
</div>
|
||||
<div class="bg-gray-800 rounded-lg shadow p-6 mb-6">
|
||||
{{ form_start(form) }}
|
||||
<div class="flex space-x-4">
|
||||
<div class="flex-1">
|
||||
{{ form_row(form.raisonSocial) }}
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
{{ form_row(form.name) }}
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
{{ form_row(form.surname) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex space-x-4">
|
||||
<div class="flex-1">
|
||||
{{ form_row(form.email) }}
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
{{ form_row(form.phone) }}
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
{{ form_row(form.parent) }}
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="w-full bg-purple-600 hover:bg-purple-700 text-white font-semibold px-4 py-2 rounded">Enregistrer</button>
|
||||
|
||||
{{ form_end(form) }}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user