auftragsdetails
Some checks failed
Gitea Actions / Run-Tests-On-Amd64 (push) Failing after 17m53s
Gitea Actions / Merge (push) Failing after 1s
Gitea Actions / Run-Tests-On-Arm64 (push) Has been cancelled

This commit is contained in:
Thomas Peterson 2026-07-14 17:04:29 +02:00
parent 5f1a673577
commit 77968d24fc
19 changed files with 2206 additions and 4079 deletions

View File

@ -0,0 +1,178 @@
# Plan: ContactBundle Tailwind-Migration + Passwort-Reset
## Übersicht
Das ContactBundle (Kundenbereich) wird von Bootstrap 5 auf Tailwind CSS umgestellt, analog zur SettingsBundle-Referenz. Das Passwort-Feld wird aus dem Edit-Formular entfernt (bleibt im Create-Formular) und durch eine separate "Passwort neu setzen"-Seite ersetzt.
## Aktueller Stand
- **Bereits Tailwind**: `list/index.html.twig`, `edit/delete.html.twig`
- **Noch Bootstrap**: `edit/edit.html.twig`, `edit/create.html.twig`, `edit/anonymisieren.html.twig`, `addressdetail/*`, `addressimport/*`, `upload/deleteAll.html.twig`
- **Base Template**: `backend_tailwind_base.html.twig` (Tailwind) statt `backend_base.html.twig` (Bootstrap)
- **Form Theme**: `tailwind_formtheme.html.twig`
---
## Phase 1: Passwort-Feld entfernen + Reset-Seite erstellen
### 1.1 Passwort-Feld nur aus Edit-Template entfernen
- **Edit-Template**: `Resources/views/backend/edit/edit.html.twig` (Zeilen ~91-107) - Passwort-Block mit data-pw-wrap entfernen
- **Create-Template**: Passwort-Feld BLEIBT erhalten (Neuanlage mit Passwort möglich)
- **ContactType.php**: `->add('password', ...)` bleibt (wird von Create noch benötigt)
### 1.2 Passwort-Logik im EditController
- Bestehende Logik bleibt: `if ($form->get('password')->getData() !== null) { ... }` (Zeilen ~347-349)
- Wird nur noch beim Create aufgerufen, da Edit das Feld nicht mehr hat
### 1.3 Neue "Passwort neu setzen"-Seite erstellen
#### Controller-Action in EditController hinzufügen
**Datei**: `Controller/Backend/EditController.php`
- Neue Action `resetPasswordAction(Request $request, Contact $contact, DocumentManager $dm)`
- Route: `/backend/contact/edit/reset-password/{uuid}`
- Name: `psc_shop_contact_backend_reset_password`
- **GET**: Zeigt Formular mit Passwort-Eingabefeld (mit Show/Hide Toggle)
- **POST**: Hasht das eingegebene Passwort mit `password_hash(PASSWORD_DEFAULT)` und speichert es
- Zeigt nach erfolgreichem Speichern eine Bestätigung
#### Neues Template erstellen
**Datei**: `Resources/views/backend/edit/reset_password.html.twig`
- Extends `backend_tailwind_base.html.twig`
- Formular mit Passwort-Eingabefeld (mit Show/Hide Toggle)
- Speichern-Button
- Bestätigungsmeldung nach erfolgreichem Speichern
- Zurück-Button zum Kunden
- Styling analog zu `delete.html.twig` (Karte mit Kopfzeile)
### 1.4 "Passwort neu setzen"-Button in Edit-Formular
**Datei**: `Resources/views/backend/edit/edit.html.twig` (nach Tailwind-Migration)
- Statt Passwort-Feld: Button "Passwort neu setzen" der zur Reset-Seite führt
- Styling: `inline-flex items-center gap-1.5 px-3 py-2 rounded-sm text-sm font-medium text-gray-700 bg-white border border-gray-300 hover:bg-gray-50 shadow-sm`
---
## Phase 2: edit.html.twig Tailwind-Migration (1746 Zeilen)
### 2.1 Base-Template wechseln
- `{% extends 'backend_base.html.twig' %}``{% extends 'backend_tailwind_base.html.twig' %}`
- Form-Theme: `{% form_theme form ... %}` auf `tailwind_formtheme.html.twig` setzen
### 2.2 Seitenstruktur
```
{% block header %}
Titel + Aktionsbuttons (Speichern, Löschen, Anonymisieren)
{% endblock %}
{% block body %}
<div class="w-full">
Tab-Navigation (sidebar links) + Tab-Inhalte (rechts)
</div>
{% endblock %}
```
### 2.3 Tab-System (aus SettingsBundle übernehmen)
- Tab-Sidebar: `tab-group flex-none md:flex w-full`
- Tab-Links: `tab-link flex items-center text-sm px-4 py-2 relative`
- Tab-Inhalte: `tab-content w-full text-stone-500 text-sm hidden/block`
### 2.4 Tabs die migriert werden müssen
1. **Allgemein** - Username, Email, Enable, Level, Shops, PriceFactor
2. **Adressdaten** - Adresstabelle (existierende Tailwind-Tabelle nutzen)
3. **Individualisierung** - Custom fields
4. **Kalkulationsvariablen** - Preisanpassungen
5. **Variablenfelder** - basketfield1/2, Freefields
6. **Zugriffsrechte** - Rollen, Berechtigungen
7. **Erweitert** - Zusätzliche Einstellungen
8. **Plugin-Tabs** - Dynamisch aus Plugin-System
### 2.5 Bootstrap → Tailwind Klassen-Mapping
| Bootstrap | Tailwind |
|-----------|----------|
| `panel panel-default > header/body` | `rounded-md border bg-white px-7.5 py-6 shadow-lg` |
| `row > col-md-*` | `flex flex-wrap > w-full lg:w-6/12 px-4` |
| `form-control` | `border-1 px-3 py-3 bg-white rounded text-sm shadow` |
| `form-control-label` | `block uppercase text-xs font-bold mb-2` |
| `btn btn-primary` | `bg-psc-500 hover:bg-psc-600 text-white rounded-sm px-4 py-1` |
| `btn btn-danger` | `bg-red-600 hover:bg-red-700 text-white rounded-sm px-4 py-2` |
| `btn btn-info` | `bg-blue-600 hover:bg-blue-700 text-white rounded-sm px-4 py-2` |
| `nav nav-pills > nav-item > nav-link` | `tab-link flex items-center text-sm px-4 py-2 relative` |
| `table table-striped` | `min-w-full text-sm` mit `hover:bg-gray-50` |
| `badge bg-success/danger` | `text-green-600` / `text-red-600` |
| `collapse` | Alpine.js `x-show` oder `hidden` Klasse |
### 2.6 JavaScript anpassen
- AJAX Username-Check: Muss weiter funktionieren
- Tab-Switching: Bereits in `backend_tailwind_base.html.twig` implementiert
- jQuery durch Vanilla JS/Alpine.js ersetzen wo nötig
---
## Phase 3: create.html.twig Tailwind-Migration (1617 Zeilen)
- Fast identisch zu edit.html.twig
- Keine Adresstabelle, kein Change-Log
- Keine Plugin-Tabs
- Preis-Tab (priceFactor) vorhanden
- Gleiche Bootstrap → Tailwind Konvertierung
---
## Phase 4: Weitere Templates migrieren
### 4.1 anonymisieren.html.twig (38 Zeilen)
- Analog zu `delete.html.twig` (bereits Tailwind)
- Bestätigungsdialog mit Ja/Nein Buttons
### 4.2 addressdetail/edit.html.twig (320 Zeilen)
- Formularfelder: type, UUID, homepage, sort, email, KundenNr, company, salutation, name, street, zip, phone, fax, mobile, ustid, steuerid, lid, zusatz1/2
- Change-Log Tabelle
- 2-Spalten Layout mit `flex flex-wrap`
### 4.3 addressdetail/create.html.twig (296 Zeilen)
- Wie edit aber ohne Change-Log
### 4.4 addressdetail/delete.html.twig (40 Zeilen)
- Analog zu bestehender delete.html.twig
### 4.5 addressimport/step1-3.html.twig (39+86+41 Zeilen)
- Step 1: Datei-Upload
- Step 2: Spalten-Mapping
- Step 3: Bestätigung
### 4.6 upload/deleteAll.html.twig (74 Zeilen)
- Tabelle mit Uploads + Bestätigung
---
## Betroffene Dateien (Zusammenfassung)
### Zu bearbeiten:
1. `src/PSC/Shop/ContactBundle/Controller/Backend/EditController.php` - Reset-Action hinzufügen
2. `src/PSC/Shop/ContactBundle/Resources/views/backend/edit/edit.html.twig` - Tailwind + Passwort-Button statt Passwort-Feld
3. `src/PSC/Shop/ContactBundle/Resources/views/backend/edit/create.html.twig` - Tailwind (Passwort-Feld bleibt)
4. `src/PSC/Shop/ContactBundle/Resources/views/backend/edit/anonymisieren.html.twig` - Tailwind
5. `src/PSC/Shop/ContactBundle/Resources/views/backend/addressdetail/edit.html.twig` - Tailwind
6. `src/PSC/Shop/ContactBundle/Resources/views/backend/addressdetail/create.html.twig` - Tailwind
7. `src/PSC/Shop/ContactBundle/Resources/views/backend/addressdetail/delete.html.twig` - Tailwind
8. `src/PSC/Shop/ContactBundle/Resources/views/backend/addressimport/step1.html.twig` - Tailwind
9. `src/PSC/Shop/ContactBundle/Resources/views/backend/addressimport/step2.html.twig` - Tailwind
10. `src/PSC/Shop/ContactBundle/Resources/views/backend/addressimport/step3.html.twig` - Tailwind
11. `src/PSC/Shop/ContactBundle/Resources/views/backend/upload/deleteAll.html.twig` - Tailwind
### Neu erstellen:
12. `src/PSC/Shop/ContactBundle/Resources/views/backend/edit/reset_password.html.twig` - Neue Reset-Seite
### NICHT bearbeiten:
- `src/PSC/Shop/ContactBundle/Form/Backend/General/ContactType.php` - bleibt unverändert (Passwort-Feld für Create benötigt)
---
## Verifikation
1. **Kundenliste**: `/backend/contact/list/index` laden - funktioniert bereits
2. **Kunde bearbeiten**: `/backend/contact/edit/edit/{uuid}` - Tailwind-Layout prüfen
3. **Kunde anlegen**: `/backend/contact/edit/create` - Tailwind-Layout prüfen
4. **Passwort-Reset**: "Passwort neu setzen" Button klicken → Reset-Seite → Neues Passwort anzeigen
5. **Adresse bearbeiten**: `/backend/contact/address/detail/edit/{uuid}` - Tailwind prüfen
6. **Adresse anlegen**: `/backend/contact/address/detail/create/{uuid}` - Tailwind prüfen
7. **Löschen/Anonymisieren**: Bestätigungsdialoge prüfen
8. **Tabs**: Alle Tabs durchklicken, Inhalte sichtbar/versteckt korrekt
9. **Formulare speichern**: Alle Formulare testweise absenden

View File

@ -1 +1 @@
{"pid":2966987,"startedAt":1783596410229} {"pid":187559,"startedAt":1783930446903}

View File

@ -476,7 +476,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* datetime?: array{ * datetime?: array{
* default_format?: scalar|Param|null, // Default: "Y-m-d\\TH:i:sP" * default_format?: scalar|Param|null, // Default: "Y-m-d\\TH:i:sP"
* default_deserialization_formats?: list<scalar|Param|null>, * default_deserialization_formats?: list<scalar|Param|null>,
* default_timezone?: scalar|Param|null, // Default: "UTC" * default_timezone?: scalar|Param|null, // Default: "Europe/Berlin"
* cdata?: scalar|Param|null, // Default: true * cdata?: scalar|Param|null, // Default: true
* }, * },
* array_collection?: array{ * array_collection?: array{
@ -576,7 +576,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* datetime?: array{ * datetime?: array{
* default_format?: scalar|Param|null, // Default: "Y-m-d\\TH:i:sP" * default_format?: scalar|Param|null, // Default: "Y-m-d\\TH:i:sP"
* default_deserialization_formats?: list<scalar|Param|null>, * default_deserialization_formats?: list<scalar|Param|null>,
* default_timezone?: scalar|Param|null, // Default: "UTC" * default_timezone?: scalar|Param|null, // Default: "Europe/Berlin"
* cdata?: scalar|Param|null, // Default: true * cdata?: scalar|Param|null, // Default: true
* }, * },
* array_collection?: array{ * array_collection?: array{

View File

@ -646,6 +646,41 @@ class EditController extends AbstractController
); );
} }
#[Route(path: '/edit/reset-password/{uuid}', name: 'psc_shop_contact_backend_reset_password')]
#[Template('@PSCShopContact/backend/edit/reset_password.html.twig')]
#[IsGranted('ROLE_SHOP')]
public function resetPasswordAction(
Request $request,
EntityManagerInterface $entityManager,
$uuid = ""
) {
/** @var Contact $contact */
$contact = $entityManager
->getRepository('PSC\Shop\EntityBundle\Entity\Contact')
->findOneBy(array('uuid' => $uuid));
if (!$contact) {
throw $this->createNotFoundException('Kunde nicht gefunden.');
}
$saved = false;
if ($request->isMethod('POST')) {
$newPassword = $request->request->get('password', '');
if (strlen($newPassword) >= 4) {
$contact->setPassword(password_hash($newPassword, PASSWORD_DEFAULT));
$entityManager->persist($contact);
$entityManager->flush();
$saved = true;
}
}
return array(
'contact' => $contact,
'saved' => $saved,
);
}
/** /**
* @param array... $arrayCollections * @param array... $arrayCollections
* @return ArrayCollection * @return ArrayCollection

View File

@ -1,10 +1,11 @@
general: Allgemein general: Allgemein
art: Art art: Art
add: anlegen add: anlegen
back: Zurück
steuerid: Steuer Nr steuerid: Steuer Nr
lid: Leitweg Id lid: Leitweg Id
detail: bearbeiten detail: bearbeiten
customeraddress: Kunde customeraddress: Kundenadresse
Company: Firma Company: Firma
Company2: Firma Zusatz Company2: Firma Zusatz
salutations: Anrede salutations: Anrede

View File

@ -2,6 +2,7 @@ general: General
art: Art art: Art
detail: edit detail: edit
add: Add add: Add
back: Back
customeraddress: Customer address customeraddress: Customer address
Company: Company Company: Company
Companyaddition: Company Addition Companyaddition: Company Addition

View File

@ -1,296 +1,83 @@
{% extends 'backend_base.html.twig' %} {% extends 'backend_tailwind_base.html.twig' %}
{% form_theme form 'tailwind_formtheme.html.twig' %}
{% trans_default_domain 'core_contact_detail_create_and_edit' %} {% trans_default_domain 'core_contact_detail_create_and_edit' %}
{% block header %}
<div>
<h1 class="text-psc text-2xl font-medium flex flex-row items-baseline gap-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-8 self-center">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" />
</svg>
{{ 'customeraddress'|trans }} <span class="text-gray-500">{{ 'add'|trans }}</span>
<span class="text-gray-400 text-base ml-2">für {{ contact.username }}</span>
</h1>
</div>
<div class="flex flex-wrap items-center gap-4 justify-start shrink-0">
<a href="{{ path("psc_shop_contact_backend_edit", {uuid: contact.uuid}) }}" class="inline-flex items-center justify-center py-1 gap-1 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-gray-500 hover:bg-gray-600 hover:ring-2 hover:ring-gray-500 hover:ring-offset-2 min-h-[2.25rem]">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="button-icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" />
</svg>
{{ 'back'|trans }}
</a>
</div>
{% endblock %}
{% block body %} {% block body %}
<div class="header"> <div class="flex flex-col gap-6">
<div class="row"> {{ form_start(form) }}
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6"> <div class="rounded-md border bg-white px-7.5 py-6 shadow-lg">
<h3>
<i class="fa-fw fa fa-user"></i>
{{ 'customeraddress'|trans }} <span>>
{{ 'add'|trans }} </span>
</h3>
</div>
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 text-end">
<a href="{{ path("psc_shop_contact_backend_edit", {uuid: contact.uuid}) }}" class="btn btn-default btn-sm"><i class="fa fa-lg fa-fw fa-arrow-left"></i> {{ 'back'|trans }}</a>
</div>
</div>
</div>
<div class="body">
<div class="panel">
<div class="header">
<h5>{{ contact.username }}</h5>
</div>
<div class="body">
{{ form_start(form, { 'attr': {'class': 'smart-form'}}) }}
{{ form_errors(form) }} {{ form_errors(form) }}
<div class="row"> <div class="flex flex-wrap mb-4">
<div class="col-md-6"> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.type) }}</div>
<div class="row mb-3"> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.pos) }}</div>
<label class="col-md-3 form-control-label"> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.kundenNr) }}</div>
{{ form_label(form.type) }} <div class="w-full lg:w-3/12 px-4">{{ form_row(form.uuid) }}</div>
</label>
<div class="col-md-9">
{{ form_widget(form.type) }}
</div>
{{ form_errors(form.type) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.uuid) }}
</label>
<div class="col-md-9">
{{ form_widget(form.uuid, {attr: {'class': 'form-control disabled'}}) }}
</div>
{{ form_errors(form.uuid) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.homepage) }}
</label>
<div class="col-md-9">
{{ form_widget(form.homepage) }}
</div>
{{ form_errors(form.homepage) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.pos) }}
</label>
<div class="col-md-9">
{{ form_widget(form.pos) }}
</div>
{{ form_errors(form.pos) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.email) }}
</label>
<div class="col-md-9">
{{ form_widget(form.email) }}
</div>
{{ form_errors(form.email) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.kundenNr) }}
</label>
<div class="col-md-9">
{{ form_widget(form.kundenNr) }}
</div>
{{ form_errors(form.kundenNr) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.company) }}
</label>
<div class="col-md-9">
{{ form_widget(form.company) }}
</div>
{{ form_errors(form.company) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.company2) }}
</label>
<div class="col-md-9">
{{ form_widget(form.company2) }}
</div>
{{ form_errors(form.company2) }}
</div>
</div>
</div> </div>
<div class="row"> <div class="flex flex-wrap mb-4">
<div class="col-md-6"> <div class="w-full lg:w-6/12 px-4">{{ form_row(form.company) }}</div>
<div class="row mb-3"> <div class="w-full lg:w-6/12 px-4">{{ form_row(form.company2) }}</div>
<label class="col-md-3 form-control-label">
{{ form_label(form.firstname) }}
</label>
<div class="col-md-3">
{{ form_widget(form.salutation) }}
</div>
<div class="col-md-6">
{{ form_widget(form.firstname) }}
</div>
{{ form_errors(form.firstname) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.lastname) }}
</label>
<div class="col-md-9">
{{ form_widget(form.lastname) }}
</div>
{{ form_errors(form.lastname) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.street) }}/{{ form_label(form.houseNumber) }}
</label>
<div class="col-md-6">
{{ form_widget(form.street) }}
</div> </div>
<div class="col-md-3"> <div class="flex flex-wrap mb-4">
{{ form_widget(form.houseNumber) }} <div class="w-full lg:w-2/12 px-4">{{ form_row(form.salutation) }}</div>
</div> <div class="w-full lg:w-5/12 px-4">{{ form_row(form.firstname) }}</div>
{{ form_errors(form.street) }}{{ form_errors(form.houseNumber) }} <div class="w-full lg:w-5/12 px-4">{{ form_row(form.lastname) }}</div>
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.zip) }}/{{ form_label(form.city) }}/{{ form_label(form.country) }}
</label>
<div class="col-md-2">
{{ form_widget(form.zip) }}
</div>
<div class="col-md-4">
{{ form_widget(form.city) }}
</div>
<div class="col-md-3">
{{ form_widget(form.country) }}
</div>
{{ form_errors(form.zip) }}
{{ form_errors(form.city) }}
{{ form_errors(form.country) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.phone) }}
</label>
<div class="col-md-9">
{{ form_widget(form.phone) }}
</div>
{{ form_errors(form.phone) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.fax) }}
</label>
<div class="col-md-9">
{{ form_widget(form.fax) }}
</div>
{{ form_errors(form.fax) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.mobilPhone) }}
</label>
<div class="col-md-9">
{{ form_widget(form.mobilPhone) }}
</div>
{{ form_errors(form.mobilPhone) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.ustid) }}
</label>
<div class="col-md-9">
{{ form_widget(form.ustid) }}
</div>
{{ form_errors(form.ustid) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.steuerid) }}
</label>
<div class="col-md-9">
{{ form_widget(form.steuerid) }}
</div>
{{ form_errors(form.steuerid) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.lid) }}
</label>
<div class="col-md-9">
{{ form_widget(form.lid) }}
</div>
{{ form_errors(form.lid) }}
</div>
</div>
</div> </div>
<div class="row"> <div class="flex flex-wrap mb-4">
<div class="col-md-6"> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.street) }}</div>
<div class="row mb-3"> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.houseNumber) }}</div>
<label class="col-md-3 form-control-label"> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.zip) }}</div>
{{ form_label(form.zusatz1) }} <div class="w-full lg:w-3/12 px-4">{{ form_row(form.city) }}</div>
</label>
<div class="col-md-9">
{{ form_widget(form.zusatz1) }}
</div> </div>
{{ form_errors(form.zusatz1) }}
<div class="flex flex-wrap mb-4">
<div class="w-full lg:w-3/12 px-4">{{ form_row(form.country) }}</div>
<div class="w-full lg:w-3/12 px-4">{{ form_row(form.phone) }}</div>
<div class="w-full lg:w-3/12 px-4">{{ form_row(form.fax) }}</div>
<div class="w-full lg:w-3/12 px-4">{{ form_row(form.mobilPhone) }}</div>
</div> </div>
<div class="flex flex-wrap mb-4">
<div class="w-full lg:w-4/12 px-4">{{ form_row(form.email) }}</div>
<div class="w-full lg:w-4/12 px-4">{{ form_row(form.homepage) }}</div>
<div class="w-full lg:w-4/12 px-4">{{ form_row(form.ustid) }}</div>
</div> </div>
<div class="col-md-6">
<div class="row mb-3"> <div class="flex flex-wrap">
<label class="col-md-3 form-control-label"> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.steuerid) }}</div>
{{ form_label(form.zusatz2) }} <div class="w-full lg:w-3/12 px-4">{{ form_row(form.lid) }}</div>
</label> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.zusatz1) }}</div>
<div class="col-md-9"> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.zusatz2) }}</div>
{{ form_widget(form.zusatz2) }}
</div> </div>
{{ form_errors(form.zusatz2) }}
</div>
</div>
</div>
<div class="row mb-3">
<div class="text-end">
{{ form_widget(form.save, {attr: {class: 'btn btn-primary btn-sm'}}) }}
</div> </div>
<div class="text-end my-2">
{{ form_widget(form.save, {attr: {class: 'inline-flex items-center justify-center py-1 gap-1 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-psc-500 hover:bg-psc-600 hover:ring-2 hover:ring-psc-500 hover:ring-offset-2 min-h-[2.25rem]'}}) }}
</div> </div>
{{ form_end(form) }} {{ form_end(form) }}
</div> </div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -1,37 +1,54 @@
{% extends 'backend_base.html.twig' %} {% extends 'backend_tailwind_base.html.twig' %}
{% trans_default_domain 'core_contact_delete' %} {% trans_default_domain 'core_contact_delete' %}
{% block header %}
<div>
<h1 class="text-psc text-2xl font-medium flex flex-row gap-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-8">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" />
</svg>
{{'address'|trans}} <span class="text-gray-500">{{'del'|trans}}</span>
</h1>
</div>
<div class="flex flex-wrap items-center gap-4 justify-start shrink-0">
<a href="{{ path("psc_shop_contact_backend_edit", {uuid: contact.uuid}) }}" class="inline-flex items-center justify-center py-1 gap-1 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-gray-500 hover:bg-gray-600 hover:ring-2 hover:ring-gray-500 hover:ring-offset-2 min-h-[2.25rem]">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="button-icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" />
</svg>
{{'back'|trans}}
</a>
</div>
{% endblock %}
{% block body %} {% block body %}
<div class="header"> <div class="flex flex-col gap-6">
<div class="row"> <div class="rounded-md border border-red-200 bg-white shadow-lg max-w-xl">
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6"> <div class="border-b border-red-200 bg-red-50 px-6 py-4">
<h3> <div class="flex items-center gap-3">
<i class="fa-fw fa fa-user"></i> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 text-red-600">
{{ 'address'|trans }} <span>> <path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" />
{{ 'del'|trans }}</span> </svg>
<h3 class="text-xl font-medium text-red-900">
{{'addressdel'|trans}}
</h3> </h3>
</div> </div>
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 text-end">
<a href="{{ path("psc_shop_contact_backend_edit", {uuid: contact.uuid}) }}" class="btn btn-default btn-sm"><i class="fa fa-lg fa-fw fa-arrow-left"></i> {{ 'back'|trans }}</a>
</div>
</div>
</div> </div>
<div class="body"> <div class="border-t border-gray-200 px-6 py-4 bg-gray-50">
<div class="panel"> {{ form_start(form) }}
<div class="header"> <div class="flex flex-wrap items-center gap-3 justify-end">
<h4>{{ 'addressdel'|trans }}</h4> {{ form_widget(form.no, {
</div> attr: {
<div class="body"> class: 'inline-flex items-center justify-center py-2 gap-2 font-medium rounded-md px-4 text-sm text-psc-600 border border-psc-500 bg-white hover:bg-gray-50 hover:ring-2 hover:ring-psc-500 hover:ring-offset-1 shadow-sm'
},
{{ form_start(form, { 'attr': {'class': ''}}) }} label: 'no'|trans
<div class="row mb-3"> }) }}
<label class="col-md-1 form-control-label"></label> {{ form_widget(form.yes, {
<div class="col-md-1"> attr: {
{{ form_widget(form.yes, {attr: {class: 'btn btn-lg btn-warning btn-sm'}}) }} class: 'inline-flex items-center justify-center py-2 gap-2 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-red-500 hover:bg-red-600 hover:ring-2 hover:ring-red-500 hover:ring-offset-1'
</div> },
<div class="col-md-1"> label: 'yes'|trans
{{ form_widget(form.no, {attr: {class: 'btn btn-lg btn-primary btn-sm'}}) }} }) }}
</div>
</div> </div>
{{ form_end(form) }} {{ form_end(form) }}
</div> </div>

View File

@ -1,320 +1,118 @@
{% extends 'backend_base.html.twig' %} {% extends 'backend_tailwind_base.html.twig' %}
{% form_theme form 'tailwind_formtheme.html.twig' %}
{% trans_default_domain 'core_contact_detail_create_and_edit' %} {% trans_default_domain 'core_contact_detail_create_and_edit' %}
{% block header %}
<div>
<h1 class="text-psc text-2xl font-medium flex flex-row items-baseline gap-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-8 self-center">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" />
</svg>
{{ 'customeraddress'|trans }} <span class="text-gray-500">{{ 'detail'|trans }}</span>
<span class="text-gray-400 text-base ml-2">ID: {{ contactAddress.uid }} · für {{ contact.username }}</span>
</h1>
</div>
<div class="flex flex-wrap items-center gap-4 justify-start shrink-0">
<a href="{{ path("psc_shop_contact_backend_edit", {uuid: contact.uuid}) }}" class="inline-flex items-center justify-center py-1 gap-1 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-gray-500 hover:bg-gray-600 hover:ring-2 hover:ring-gray-500 hover:ring-offset-2 min-h-[2.25rem]">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="button-icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" />
</svg>
{{ 'back'|trans }}
</a>
</div>
{% endblock %}
{% block body %} {% block body %}
<div class="header"> <div class="flex flex-col gap-6">
<div class="row"> {{ form_start(form) }}
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6"> <div class="rounded-md border bg-white px-7.5 py-6 shadow-lg">
<h3>
<i class="fa-fw fa fa-user"></i>
{{ 'customeraddress'|trans }} <span>>
{{ 'detail'|trans }} </span> {{ contactAddress.uid }}
</h3>
</div>
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 text-end">
<a href="{{ path("psc_shop_contact_backend_edit", {uuid: contact.uuid}) }}" class="btn btn-default btn-sm"><i class="fa fa-lg fa-fw fa-arrow-left"></i> Zurück</a>
</div>
</div>
</div>
<div class="body">
<div class="panel">
<div class="header">
<h5>{{ contact.username }}</h5>
</div>
<div class="body">
{{ form_start(form, { 'attr': {'class': 'smart-form'}}) }}
{{ form_errors(form) }} {{ form_errors(form) }}
<div class="row"> <div class="flex flex-wrap mb-4">
<div class="col-md-6"> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.type) }}</div>
<div class="row mb-3"> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.pos) }}</div>
<label class="col-md-3 form-control-label"> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.kundenNr) }}</div>
{{ form_label(form.type) }} <div class="w-full lg:w-3/12 px-4">{{ form_row(form.uuid) }}</div>
</label>
<div class="col-md-9">
{{ form_widget(form.type) }}
</div>
{{ form_errors(form.type) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.uuid) }}
</label>
<div class="col-md-9">
{{ form_widget(form.uuid, {attr: {'class': 'form-control disabled'}}) }}
</div>
{{ form_errors(form.uuid) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.homepage) }}
</label>
<div class="col-md-9">
{{ form_widget(form.homepage) }}
</div>
{{ form_errors(form.homepage) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.pos) }}
</label>
<div class="col-md-9">
{{ form_widget(form.pos) }}
</div>
{{ form_errors(form.pos) }}
</div>
</div>
</div> </div>
<div class="row"> <div class="flex flex-wrap mb-4">
<div class="col-md-6"> <div class="w-full lg:w-6/12 px-4">{{ form_row(form.company) }}</div>
<div class="row mb-3"> <div class="w-full lg:w-6/12 px-4">{{ form_row(form.company2) }}</div>
<label class="col-md-3 form-control-label">
{{ form_label(form.email) }}
</label>
<div class="col-md-9">
{{ form_widget(form.email) }}
</div>
{{ form_errors(form.email) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.kundenNr) }}
</label>
<div class="col-md-9">
{{ form_widget(form.kundenNr) }}
</div>
{{ form_errors(form.kundenNr) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.company) }}
</label>
<div class="col-md-9">
{{ form_widget(form.company) }}
</div>
{{ form_errors(form.company) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.company2) }}
</label>
<div class="col-md-9">
{{ form_widget(form.company2) }}
</div>
{{ form_errors(form.company2) }}
</div>
</div>
</div> </div>
<div class="row"> <div class="flex flex-wrap mb-4">
<div class="col-md-6"> <div class="w-full lg:w-2/12 px-4">{{ form_row(form.salutation) }}</div>
<div class="row mb-3"> <div class="w-full lg:w-5/12 px-4">{{ form_row(form.firstname) }}</div>
<label class="col-md-3 form-control-label"> <div class="w-full lg:w-5/12 px-4">{{ form_row(form.lastname) }}</div>
{{ form_label(form.firstname) }}
</label>
<div class="col-md-3">
{{ form_widget(form.salutation) }}
</div>
<div class="col-md-6">
{{ form_widget(form.firstname) }}
</div>
{{ form_errors(form.firstname) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.lastname) }}
</label>
<div class="col-md-9">
{{ form_widget(form.lastname) }}
</div>
{{ form_errors(form.lastname) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.street) }}/{{ form_label(form.houseNumber) }}
</label>
<div class="col-md-6">
{{ form_widget(form.street) }}
</div> </div>
<div class="col-md-3"> <div class="flex flex-wrap mb-4">
{{ form_widget(form.houseNumber) }} <div class="w-full lg:w-3/12 px-4">{{ form_row(form.street) }}</div>
</div> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.houseNumber) }}</div>
{{ form_errors(form.street) }}{{ form_errors(form.houseNumber) }} <div class="w-full lg:w-3/12 px-4">{{ form_row(form.zip) }}</div>
</div> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.city) }}</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.zip) }}/{{ form_label(form.city) }}/{{ form_label(form.country) }}
</label>
<div class="col-md-2">
{{ form_widget(form.zip) }}
</div>
<div class="col-md-4">
{{ form_widget(form.city) }}
</div>
<div class="col-md-3">
{{ form_widget(form.country) }}
</div>
{{ form_errors(form.zip) }}
{{ form_errors(form.city) }}
{{ form_errors(form.country) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.phone) }}
</label>
<div class="col-md-9">
{{ form_widget(form.phone) }}
</div>
{{ form_errors(form.phone) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.fax) }}
</label>
<div class="col-md-9">
{{ form_widget(form.fax) }}
</div>
{{ form_errors(form.fax) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.mobilPhone) }}
</label>
<div class="col-md-9">
{{ form_widget(form.mobilPhone) }}
</div>
{{ form_errors(form.mobilPhone) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.ustid) }}
</label>
<div class="col-md-9">
{{ form_widget(form.ustid) }}
</div>
{{ form_errors(form.ustid) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.steuerid) }}
</label>
<div class="col-md-9">
{{ form_widget(form.steuerid) }}
</div>
{{ form_errors(form.steuerid) }}
</div>
</div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.lid) }}
</label>
<div class="col-md-9">
{{ form_widget(form.lid) }}
</div>
{{ form_errors(form.lid) }}
</div>
</div>
</div> </div>
<div class="row"> <div class="flex flex-wrap mb-4">
<div class="col-md-6"> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.country) }}</div>
<div class="row mb-3"> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.phone) }}</div>
<label class="col-md-3 form-control-label"> <div class="w-full lg:w-3/12 px-4">{{ form_row(form.fax) }}</div>
{{ form_label(form.zusatz1) }} <div class="w-full lg:w-3/12 px-4">{{ form_row(form.mobilPhone) }}</div>
</label>
<div class="col-md-9">
{{ form_widget(form.zusatz1) }}
</div> </div>
{{ form_errors(form.zusatz1) }}
<div class="flex flex-wrap mb-4">
<div class="w-full lg:w-4/12 px-4">{{ form_row(form.email) }}</div>
<div class="w-full lg:w-4/12 px-4">{{ form_row(form.homepage) }}</div>
<div class="w-full lg:w-4/12 px-4">{{ form_row(form.ustid) }}</div>
</div> </div>
<div class="flex flex-wrap">
<div class="w-full lg:w-3/12 px-4">{{ form_row(form.steuerid) }}</div>
<div class="w-full lg:w-3/12 px-4">{{ form_row(form.lid) }}</div>
<div class="w-full lg:w-3/12 px-4">{{ form_row(form.zusatz1) }}</div>
<div class="w-full lg:w-3/12 px-4">{{ form_row(form.zusatz2) }}</div>
</div> </div>
<div class="col-md-6">
<div class="row mb-3">
<label class="col-md-3 form-control-label">
{{ form_label(form.zusatz2) }}
</label>
<div class="col-md-9">
{{ form_widget(form.zusatz2) }}
</div>
{{ form_errors(form.zusatz2) }}
</div>
</div>
</div>
<div class="row mb-3">
<div class="text-end">
{{ form_widget(form.save, {attr: {class: 'btn btn-primary btn-sm'}}) }}
</div> </div>
<div class="text-end my-2">
{{ form_widget(form.save, {attr: {class: 'inline-flex items-center justify-center py-1 gap-1 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-psc-500 hover:bg-psc-600 hover:ring-2 hover:ring-psc-500 hover:ring-offset-2 min-h-[2.25rem]'}}) }}
</div> </div>
{{ form_end(form) }} {{ form_end(form) }}
<div class="rounded-md border bg-white shadow-lg">
<div class="px-6 py-4 border-b border-gray-200">
<h2 class="text-base font-semibold text-gray-800">{{ 'Changes'|trans }}</h2>
</div> </div>
</div> <div class="overflow-x-auto">
<div class="panel"> <table class="min-w-full text-sm">
<div class="header"> <thead class="bg-slate-100 border-t border-stroke">
<h4>{{ 'Changes'|trans }}</h4> <tr>
</div> <th class="px-4 py-3 text-left font-medium text-gray-700">{{ 'Date'|trans }}</th>
<div class="body"> <th class="px-4 py-3 text-left font-medium text-gray-700">{{ 'Username'|trans }}</th>
<table class="table"> <th class="px-4 py-3 text-left font-medium text-gray-700">{{ 'Changes'|trans }}</th>
<thead> </tr>
<tr><th>{{ 'Date'|trans }}</th><th>{{ 'Username'|trans }}</th><th>{{'Changes'|trans}}</th></tr>
</thead> </thead>
<tbody> <tbody class="divide-y">
{% for change in changes %} {% for change in changes %}
<tr><td>{{ change.created|date('H:i:s d.m.Y') }}</td><td>{{ change.username }}</td><td> <tr class="hover:bg-gray-50">
<td class="px-4 py-3">{{ change.created|date('H:i:s d.m.Y') }}</td>
<td class="px-4 py-3">{{ change.username }}</td>
<td class="px-4 py-3">
{% for key,set in change.changeset %} {% for key,set in change.changeset %}
{% if set|length > 1 and set[1] is not iterable %} {% if set|length > 1 and set[1] is not iterable %}
<strong>{{key}}</strong> <span class="badge bg-danger"><del>{{ set[0]}}</del></span><span class="badge bg-success">{% if set[1] is null %}0{% else %}{{ set[1] }}{% endif %}</span></br> <strong>{{ key }}</strong>
<span class="inline-block px-2 py-0.5 text-xs font-medium rounded bg-red-100 text-red-800 line-through">{{ set[0] }}</span>
<span class="inline-block px-2 py-0.5 text-xs font-medium rounded bg-green-100 text-green-800">{% if set[1] is null %}0{% else %}{{ set[1] }}{% endif %}</span>
<br>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
<td></tr> </td>
</tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,39 +1,39 @@
{% extends 'backend_base.html.twig' %} {% extends 'backend_tailwind_base.html.twig' %}
{% block body %} {% form_theme form 'tailwind_formtheme.html.twig' %}
<div class="header">
<div class="row">
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">
<h3>
<i class="fa-fw fa fa-user"></i>
Address Import <span>>
Schritt 1 </span>
</h3>
</div>
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 text-end">
<a href="{{ path("psc_shop_contact_backend_edit", {uuid: contact.uuid}) }}" class="btn btn-default btn-sm"><i class="fa fa-lg fa-fw fa-arrow-left"></i> Zurück</a>
</div>
</div>
</div>
<div class="body"> {% block header %}
<div>
<h1 class="text-psc text-2xl font-medium flex flex-row gap-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-8">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" />
</svg>
Address Import <span class="text-gray-500">Schritt 1</span>
</h1>
</div>
<div class="flex flex-wrap items-center gap-4 justify-start shrink-0">
<a href="{{ path("psc_shop_contact_backend_edit", {uuid: contact.uuid}) }}" class="inline-flex items-center justify-center py-1 gap-1 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-gray-500 hover:bg-gray-600 hover:ring-2 hover:ring-gray-500 hover:ring-offset-2 min-h-[2.25rem]">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="button-icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" />
</svg>
Zurück
</a>
</div>
{% endblock %}
{% block body %}
<div class="flex flex-col gap-6">
<div class="rounded-md border bg-white px-7.5 py-6 shadow-lg max-w-xl">
<h5 class="text-lg font-medium text-gray-900 mb-4">{{ contact.username }}</h5>
{{ form_start(form) }} {{ form_start(form) }}
<div class="panel"> <div class="flex flex-wrap items-end gap-4">
<div class="header"> <div class="flex-1">{{ form_row(form.file) }}</div>
<h5>{{ contact.username }}</h5> <div>
</div> <button type="submit" class="inline-flex items-center justify-center py-1 gap-1 font-medium rounded-sm px-4 text-sm text-white shadow-lg bg-psc-500 hover:bg-psc-600 hover:ring-2 hover:ring-psc-500 hover:ring-offset-2 min-h-[2.25rem]">
<div class="body"> Weiter
<div class="row mb-3"> </button>
<label class="col-md-1 form-control-label"></label>
<div class="col-md-1">
{{ form_widget(form.file) }}
</div>
<div class="col-md-1">
<button type="submit">Weiter</button>
</div>
</div>
</div> </div>
</div> </div>
{{ form_end(form) }} {{ form_end(form) }}
</div> </div>
</div>
{% endblock %} {% endblock %}

View File

@ -1,86 +1,61 @@
{% extends 'backend_base.html.twig' %} {% extends 'backend_tailwind_base.html.twig' %}
{% form_theme form 'tailwind_formtheme.html.twig' %}
{% block header %}
<div>
<h1 class="text-psc text-2xl font-medium flex flex-row gap-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-8">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" />
</svg>
Address Import <span class="text-gray-500">Schritt 2</span>
</h1>
</div>
<div class="flex flex-wrap items-center gap-4 justify-start shrink-0">
<a href="{{ path("psc_shop_contact_backend_list") }}" class="inline-flex items-center justify-center py-1 gap-1 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-gray-500 hover:bg-gray-600 hover:ring-2 hover:ring-gray-500 hover:ring-offset-2 min-h-[2.25rem]">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="button-icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" />
</svg>
Zurück
</a>
</div>
{% endblock %}
{% block body %} {% block body %}
<div class="header"> <div class="flex flex-col gap-6">
<div class="row"> <div class="rounded-md border bg-white px-7.5 py-6 shadow-lg">
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6"> <h5 class="text-lg font-medium text-gray-900 mb-4">{{ contact.username }}</h5>
<h3> {{ form_start(form) }}
<i class="fa-fw fa fa-user"></i>
Address Import <span>> <div class="flex flex-wrap gap-6 mb-6">
Schritt 1 </span> <div class="w-full lg:w-4/12">{{ form_row(form.ignoreFirstLine) }}</div>
</h3> <div class="w-full lg:w-4/12">{{ form_row(form.overwrite) }}</div>
</div>
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 text-end">
<a href="{{ path("psc_shop_contact_backend_list") }}" class="btn btn-default btn-sm"><i class="fa fa-lg fa-fw fa-arrow-left"></i> Zurück</a>
</div>
</div>
</div> </div>
<div class="body"> <h6 class="text-sm mt-3 mb-4 font-bold uppercase">Mapping</h6>
{{ form_start(form) }} <div class="space-y-4">
<div class="panel">
<div class="header">
<h5>{{ contact.username }}</h5>
</div>
<div class="body">
<div class="row">
<div class="col-md-4">
<div class="row mb-3">
{{ form_label(form.ignoreFirstLine) }}
<div class="col-md-8">
{{ form_widget(form.ignoreFirstLine) }}
</div>
{{ form_errors(form.ignoreFirstLine) }}
</div>
</div>
<div class="col-md-4">
<div class="row mb-3">
{{ form_label(form.overwrite) }}
<div class="col-md-8">
{{ form_widget(form.overwrite) }}
</div>
{{ form_errors(form.overwrite) }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h4>Mapping</h4>
<span class="posFiles">
{# iterate over each existing tag and render its only field: name #}
{% for map in form.mapping %} {% for map in form.mapping %}
<div class="item"> <div class="rounded-md border border-gray-200 bg-gray-50 p-4">
<div class="row"> <div class="flex flex-wrap gap-4">
<div class="col-2"> <div class="w-full lg:w-2/12">
<label class="col-form-label form-control-label required">Key</label> <label class="block uppercase text-xs font-bold mb-2 text-gray-700">Key</label>
</div>
<div class="col-10">
{{ form_widget(map.key) }} {{ form_widget(map.key) }}
</div> </div>
</div> <div class="flex-1">
<div class="row"> <label class="block uppercase text-xs font-bold mb-2 text-gray-700">Value</label>
<div class="col-2">
<label class="col-form-label form-control-label required">Value</label>
</div>
<div class="col-10">
{{ form_widget(map.value) }} {{ form_widget(map.value) }}
</div> </div>
</div> </div>
</div> </div>
<hr/>
{% endfor %} {% endfor %}
</span>
</div>
</div> </div>
<div class="mt-6">
<button type="submit" class="inline-flex items-center justify-center py-1 gap-1 font-medium rounded-sm px-4 text-sm text-white shadow-lg bg-psc-500 hover:bg-psc-600 hover:ring-2 hover:ring-psc-500 hover:ring-offset-2 min-h-[2.25rem]">
Weiter
</button>
</div>
<div class="row mb-3">
<div class="col-md-1">
<button type="submit">Weiter</button>
</div>
</div>
</div>
</div>
{{ form_end(form) }} {{ form_end(form) }}
</div> </div>
</div>
{% endblock %} {% endblock %}

View File

@ -1,41 +1,63 @@
{% extends 'backend_base.html.twig' %} {% extends 'backend_tailwind_base.html.twig' %}
{% block header %}
<div>
<h1 class="text-psc text-2xl font-medium flex flex-row gap-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-8">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" />
</svg>
Address Import <span class="text-gray-500">Schritt 3</span>
</h1>
</div>
<div class="flex flex-wrap items-center gap-4 justify-start shrink-0">
<a href="{{ path("psc_shop_contact_backend_list") }}" class="inline-flex items-center justify-center py-1 gap-1 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-gray-500 hover:bg-gray-600 hover:ring-2 hover:ring-gray-500 hover:ring-offset-2 min-h-[2.25rem]">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="button-icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" />
</svg>
Zurück
</a>
</div>
{% endblock %}
{% block body %} {% block body %}
<div class="header"> <div class="flex flex-col gap-6">
<div class="row"> <div class="rounded-md border border-yellow-200 bg-white shadow-lg max-w-xl">
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6"> <div class="border-b border-yellow-200 bg-yellow-50 px-6 py-4">
<h3> <div class="flex items-center gap-3">
<i class="fa-fw fa fa-user"></i> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 text-yellow-600">
Address Import <span>> <path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
Schritt 3 </span> </svg>
<h3 class="text-xl font-medium text-yellow-900">
Import bestätigen
</h3> </h3>
</div> </div>
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6 text-end">
<a href="{{ path("psc_shop_contact_backend_list") }}" class="btn btn-default btn-sm"><i class="fa fa-lg fa-fw fa-arrow-left"></i> Zurück</a>
</div> </div>
<div class="px-6 py-6">
<p class="text-gray-700">
Wollen Sie wirklich in diesen Kunden importieren?
</p>
<div class="mt-4 p-4 bg-gray-50 rounded-md border border-gray-200">
<h5 class="text-lg font-medium text-gray-900">{{ contact.username }}</h5>
</div> </div>
</div> </div>
<div class="body"> <div class="border-t border-gray-200 px-6 py-4 bg-gray-50">
{{ form_start(form) }}
<div class="panel"> <div class="flex flex-wrap items-center gap-3 justify-end">
<div class="header"> {{ form_widget(form.no, {
<h5>Wollen Sie wirklich in diesen Kunden importieren? {{ contact.username }}</h5> attr: {
</div> class: 'inline-flex items-center justify-center py-2 gap-2 font-medium rounded-md px-4 text-sm text-psc-600 border border-psc-500 bg-white hover:bg-gray-50 hover:ring-2 hover:ring-psc-500 hover:ring-offset-1 shadow-sm'
<div class="body"> }
{{ form_start(form, { 'attr': {'class': ''}}) }} }) }}
<div class="row mb-3"> {{ form_widget(form.yes, {
<label class="col-md-1 form-control-label"></label> attr: {
<div class="col-md-1"> class: 'inline-flex items-center justify-center py-2 gap-2 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-psc-500 hover:bg-psc-600 hover:ring-2 hover:ring-psc-500 hover:ring-offset-1'
{{ form_widget(form.yes, {attr: {class: 'btn btn-lg btn-warning btn-sm'}}) }} }
</div> }) }}
<div class="col-md-1">
{{ form_widget(form.no, {attr: {class: 'btn btn-lg btn-primary btn-sm'}}) }}
</div>
</div> </div>
{{ form_end(form) }} {{ form_end(form) }}
</div> </div>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,35 +1,63 @@
{% extends 'backend_base.html.twig' %} {% extends 'backend_tailwind_base.html.twig' %}
{% trans_default_domain 'core_contact_anonymisieren' %} {% trans_default_domain 'core_contact_anonymisieren' %}
{% block header %}
<div>
<h1 class="text-psc text-2xl font-medium flex flex-row gap-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-8">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" />
</svg>
{{'customers'|trans}} <span class="text-gray-500">{{'Anonymize'|trans}}</span>
</h1>
</div>
<div class="flex flex-wrap items-center gap-4 justify-start shrink-0">
<a href="{{ path("psc_shop_contact_backend_edit", {uuid: contact.uuid}) }}" class="inline-flex items-center justify-center py-1 gap-1 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-gray-500 hover:bg-gray-600 hover:ring-2 hover:ring-gray-500 hover:ring-offset-2 min-h-[2.25rem]">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="button-icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" />
</svg>
{{'back'|trans}}
</a>
</div>
{% endblock %}
{% block body %} {% block body %}
<div class="header"> <div class="flex flex-col gap-6">
<div class="row"> <div class="rounded-md border border-yellow-200 bg-white shadow-lg max-w-xl">
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6"> <div class="border-b border-yellow-200 bg-yellow-50 px-6 py-4">
<h3> <div class="flex items-center gap-3">
<i class="fa-fw fa fa-user"></i> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 text-yellow-600">
{{ 'customers'|trans }} <span>> <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
{{ 'Anonymize'|trans }} </span> </svg>
<h3 class="text-xl font-medium text-yellow-900">
{{'Anonymize'|trans}}
</h3> </h3>
</div> </div>
</div> </div>
</div>
<div class="px-6 py-6">
<div class="body"> <div class="p-4 bg-gray-50 rounded-md border border-gray-200">
<div class="panel"> <h5 class="text-lg font-medium text-gray-900">{{ contact.username }}</h5>
<div class="header">
<h5>{{ contact.username }}</h5>
</div> </div>
<div class="body"> <p class="mt-4 text-gray-700">
{{ form_start(form, { 'attr': {'class': ''}}) }}
{{ form_errors(form) }}
<div class="row mb-3">
<label class="col-md-1 form-control-label">
{{'Doyoureally'|trans}} {{'Doyoureally'|trans}}
</label> </p>
<div class="col-md-11">
{{ form_widget(form.no, {attr: {class: 'btn btn-primary'}}) }}
{{ form_widget(form.yes, {attr: {class: 'btn btn-danger'}}) }}
</div> </div>
<div class="border-t border-gray-200 px-6 py-4 bg-gray-50">
{{ form_start(form) }}
<div class="flex flex-wrap items-center gap-3 justify-end">
{{ form_widget(form.no, {
attr: {
class: 'inline-flex items-center justify-center py-2 gap-2 font-medium rounded-md px-4 text-sm text-psc-600 border border-psc-500 bg-white hover:bg-gray-50 hover:ring-2 hover:ring-psc-500 hover:ring-offset-1 shadow-sm'
},
label: 'no'|trans
}) }}
{{ form_widget(form.yes, {
attr: {
class: 'inline-flex items-center justify-center py-2 gap-2 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-yellow-500 hover:bg-yellow-600 hover:ring-2 hover:ring-yellow-500 hover:ring-offset-1'
},
label: 'yes'|trans
}) }}
</div> </div>
{{ form_end(form) }} {{ form_end(form) }}
</div> </div>

View File

@ -0,0 +1,143 @@
{% extends 'backend_tailwind_base.html.twig' %}
{% trans_default_domain 'core_contact_edit' %}
{% block header %}
<div>
<h1 class="text-psc text-2xl font-medium flex flex-row gap-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-8">
<path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z" />
</svg>
{{'customers'|trans}} <span class="text-gray-500">Passwort zuruecksetzen</span>
</h1>
</div>
<div class="flex flex-wrap items-center gap-4 justify-start shrink-0">
<a href="{{ path("psc_shop_contact_backend_edit", {uuid: contact.uuid}) }}" class="inline-flex items-center justify-center py-1 gap-1 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-gray-500 hover:bg-gray-600 hover:ring-2 hover:ring-gray-500 hover:ring-offset-2 min-h-[2.25rem]">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="button-icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" />
</svg>
{{'back'|trans}}
</a>
</div>
{% endblock %}
{% block body %}
<div class="flex flex-col gap-6">
{# Password Reset Card #}
<div class="rounded-md border bg-white shadow-lg dark:border-strokedark dark:bg-boxdark max-w-xl">
{# Card Header #}
<div class="border-b border-gray-200 bg-gray-50 px-6 py-4 dark:border-strokedark dark:bg-boxdark-2">
<div class="flex items-center gap-3">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 text-psc-500">
<path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z" />
</svg>
<h3 class="text-xl font-medium text-gray-900 dark:text-bodydark">
Passwort neu setzen
</h3>
</div>
</div>
{# Card Body #}
<div class="px-6 py-6">
<div class="space-y-4">
<div class="p-4 bg-gray-50 rounded-md border border-gray-200 dark:bg-boxdark-2 dark:border-strokedark">
<h5 class="text-lg font-medium text-gray-900 dark:text-bodydark">
{{ contact.username }}
</h5>
<p class="text-sm text-gray-500 mt-1">{{ contact.email }}</p>
</div>
{% if saved %}
<div class="p-4 bg-green-50 rounded-md border border-green-200">
<div class="flex gap-3">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 text-green-600 flex-shrink-0 mt-0.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<p class="text-sm text-green-800">
Das Passwort wurde erfolgreich gespeichert.
</p>
</div>
</div>
{% else %}
<form method="post">
<div class="space-y-4">
<div>
<label for="password" class="block uppercase text-xs font-bold mb-2 text-gray-700 dark:text-bodydark">
Neues Passwort
</label>
<div class="relative" data-pw-wrap>
<input type="password" id="password" name="password" required minlength="4"
class="border-1 px-3 py-3 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150 dark:bg-boxdark dark:text-bodydark dark:border-strokedark"
style="padding-right: 2.5rem"
placeholder="Mindestens 4 Zeichen" />
<button type="button" onclick="togglePw(this)" class="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-400 hover:text-gray-600" title="Passwort anzeigen/verbergen">
<svg data-pw-eye xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" /></svg>
<svg data-pw-eye xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 hidden"><path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88" /></svg>
</button>
</div>
</div>
<div class="p-4 bg-yellow-50 rounded-md border border-yellow-200">
<div class="flex gap-3">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5 text-yellow-600 flex-shrink-0 mt-0.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
</svg>
<p class="text-sm text-yellow-800">
Das neue Passwort wird verschluesselt gespeichert und kann nicht mehr angezeigt werden.
</p>
</div>
</div>
</div>
{% endif %}
</div>
</div>
{# Card Footer with Actions #}
{% if not saved %}
<div class="border-t border-gray-200 px-6 py-4 bg-gray-50 dark:border-strokedark dark:bg-boxdark-2">
<div class="flex flex-wrap items-center gap-3 justify-end">
<a href="{{ path("psc_shop_contact_backend_edit", {uuid: contact.uuid}) }}" class="inline-flex items-center justify-center py-2 gap-2 font-medium rounded-md px-4 text-sm text-psc-600 border border-psc-500 bg-white hover:bg-gray-50 hover:ring-2 hover:ring-psc-500 hover:ring-offset-1 shadow-sm">
{{'back'|trans}}
</a>
<button type="submit" class="inline-flex items-center justify-center py-2 gap-2 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-psc-500 hover:bg-psc-600 hover:ring-2 hover:ring-psc-500 hover:ring-offset-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="button-icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z" />
</svg>
Passwort speichern
</button>
</div>
</form>
{% else %}
<div class="border-t border-gray-200 px-6 py-4 bg-gray-50 dark:border-strokedark dark:bg-boxdark-2">
<div class="flex flex-wrap items-center gap-3 justify-end">
<a href="{{ path("psc_shop_contact_backend_edit", {uuid: contact.uuid}) }}" class="inline-flex items-center justify-center py-2 gap-2 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-psc-500 hover:bg-psc-600 hover:ring-2 hover:ring-psc-500 hover:ring-offset-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="button-icon">
<path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" />
</svg>
Zurueck zum Kunden
</a>
</div>
</div>
{% endif %}
</div>
{% endif %}
</div>
</div>
<script>
function togglePw(btn) {
var wrap = btn.closest('[data-pw-wrap]');
if (!wrap) return;
var input = wrap.querySelector('input');
if (input) {
input.setAttribute('type', input.getAttribute('type') === 'password' ? 'text' : 'password');
}
wrap.querySelectorAll('[data-pw-eye]').forEach(function(svg) {
svg.classList.toggle('hidden');
});
}
</script>
{% endblock %}

View File

@ -1,74 +1,76 @@
{% extends 'backend_base.html.twig' %} {% extends 'backend_tailwind_base.html.twig' %}
{% block header %}
<div>
<h1 class="text-psc text-2xl font-medium flex flex-row gap-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="h-8">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" />
</svg>
Uploads <span class="text-gray-500">löschen</span>
</h1>
</div>
{% endblock %}
{% block body %} {% block body %}
<div class="row hidden-mobile"> <div class="flex flex-col gap-6">
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6"> <div class="rounded-md border border-red-200 bg-white shadow-lg">
<h1 class="page-title txt-color-blueDark">
<i class="fa-fw fa fa-user"></i> <div class="border-b border-red-200 bg-red-50 px-6 py-4">
Auftrag <span>> <div class="flex items-center gap-3">
Detail</span></h1> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6 text-red-600">
<path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" />
</svg>
<h3 class="text-xl font-medium text-red-900">Uploads löschen?</h3>
</div>
</div> </div>
</div> <div class="px-6 py-6">
<div class="overflow-x-auto rounded-md border border-gray-200">
<section id="widget-grid" class=""> <table class="min-w-full text-sm">
<thead class="bg-slate-50">
<!-- row --> <tr class="border-b-2 border-gray-200">
<div class="row"> <th class="px-4 py-3 text-left text-xs font-semibold text-gray-600 uppercase">File</th>
<th class="px-4 py-3 text-left text-xs font-semibold text-gray-600 uppercase">Pfad</th>
<!-- NEW WIDGET START --> <th class="px-4 py-3 text-left text-xs font-semibold text-gray-600 uppercase">Vorhanden</th>
<article class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<!-- Widget ID (each widget will need unique ID)-->
<div class="jarviswidget jarviswidget-color-darken" id="wid-id-0" data-widget-editbutton="false">
<header>
<span class="widget-icon"> <i class="fa fa-table"></i> </span>
<h2>Uploads löschen?</h2>
</header>
<div class="widget-body">
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>File</th>
<th>Pfad</th>
<th>Vorhanden</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="divide-y divide-gray-100 bg-white">
{% for orderpos in order.getPositions() %} {% for orderpos in order.getPositions() %}
{% for upload in orderpos.getUploads() %} {% for upload in orderpos.getUploads() %}
<tr><td>{{ upload.name }}</td><td>{{ upload.path }}</td><td>{% if file_exists(upload.path) %}<span class="badge bg-success">JA</span>{% else %}<span class="badge bg-danger">NEIN</span>{% endif %}</td></tr> <tr class="hover:bg-gray-50">
<td class="px-4 py-3 text-sm">{{ upload.name }}</td>
<td class="px-4 py-3 text-sm text-gray-500">{{ upload.path }}</td>
<td class="px-4 py-3">
{% if file_exists(upload.path) %}
<span class="inline-flex items-center rounded-full bg-green-100 px-2.5 py-0.5 text-xs font-medium text-green-800">JA</span>
{% else %}
<span class="inline-flex items-center rounded-full bg-red-100 px-2.5 py-0.5 text-xs font-medium text-red-800">NEIN</span>
{% endif %}
</td>
</tr>
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
{{ form_start(form, { 'attr': {'class': 'smart-form'}}) }} <div class="border-t border-gray-200 px-6 py-4 bg-gray-50">
<div class="widget-body"> {{ form_start(form) }}
<div class="row"> <div class="flex flex-wrap items-center gap-3 justify-end">
<div class="col col-1"> {{ form_widget(form.no, {
<section> attr: {
<label class="label"></label> class: 'inline-flex items-center justify-center py-2 gap-2 font-medium rounded-md px-4 text-sm text-psc-600 border border-psc-500 bg-white hover:bg-gray-50 hover:ring-2 hover:ring-psc-500 hover:ring-offset-1 shadow-sm'
<label class="input"> {{ form_widget(form.yes, {attr: {class: 'btn btn-lg btn-warning'}}) }}</label> }
</section> }) }}
</div> {{ form_widget(form.yes, {
<div class="col col-1"> attr: {
<section> class: 'inline-flex items-center justify-center py-2 gap-2 font-medium rounded-md px-4 text-sm text-white shadow-lg bg-red-500 hover:bg-red-600 hover:ring-2 hover:ring-red-500 hover:ring-offset-1'
<label class="label"></label> }
<label class="input"> {{ form_widget(form.no, {attr: {class: 'btn btn-lg btn-primary'}}) }}</label> }) }}
</section>
</div>
</div>
</div> </div>
{{ form_end(form) }} {{ form_end(form) }}
</div> </div>
</article>
</div> </div>
</section> </div>
{% endblock %} {% endblock %}

View File

@ -974,6 +974,11 @@ html {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
.my-4{
margin-top: 1rem;
margin-bottom: 1rem;
}
.mb-0{ .mb-0{
margin-bottom: 0px; margin-bottom: 0px;
} }
@ -1334,6 +1339,10 @@ html {
width: 1rem; width: 1rem;
} }
.w-4\/12{
width: 33.333333%;
}
.w-40{ .w-40{
width: 10rem; width: 10rem;
} }
@ -1366,6 +1375,10 @@ html {
width: 2rem; width: 2rem;
} }
.w-8\/12{
width: 66.666667%;
}
.w-\[var\(--sidebar-width\)\]{ .w-\[var\(--sidebar-width\)\]{
width: var(--sidebar-width); width: var(--sidebar-width);
} }
@ -1656,6 +1669,10 @@ html {
align-items: center; align-items: center;
} }
.items-baseline{
align-items: baseline;
}
.justify-start{ .justify-start{
justify-content: flex-start; justify-content: flex-start;
} }
@ -1774,6 +1791,10 @@ html {
border-color: rgb(229 231 235 / var(--tw-divide-opacity)); border-color: rgb(229 231 235 / var(--tw-divide-opacity));
} }
.self-center{
align-self: center;
}
.overflow-hidden{ .overflow-hidden{
overflow: hidden; overflow: hidden;
} }
@ -1965,6 +1986,11 @@ html {
border-color: rgb(187 247 208 / var(--tw-border-opacity)); border-color: rgb(187 247 208 / var(--tw-border-opacity));
} }
.border-green-500{
--tw-border-opacity: 1;
border-color: rgb(34 197 94 / var(--tw-border-opacity));
}
.border-psc-200{ .border-psc-200{
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(226 128 119 / var(--tw-border-opacity)); border-color: rgb(226 128 119 / var(--tw-border-opacity));
@ -2220,6 +2246,10 @@ html {
background-color: rgb(234 179 8 / var(--tw-bg-opacity)); background-color: rgb(234 179 8 / var(--tw-bg-opacity));
} }
.bg-opacity-100{
--tw-bg-opacity: 1;
}
.bg-cover{ .bg-cover{
background-size: cover; background-size: cover;
} }
@ -2715,6 +2745,11 @@ html {
color: rgb(133 77 14 / var(--tw-text-opacity)); color: rgb(133 77 14 / var(--tw-text-opacity));
} }
.text-yellow-900{
--tw-text-opacity: 1;
color: rgb(113 63 18 / var(--tw-text-opacity));
}
.underline{ .underline{
text-decoration-line: underline; text-decoration-line: underline;
} }
@ -4345,6 +4380,11 @@ html {
--tw-ring-color: rgb(239 68 68 / var(--tw-ring-opacity)); --tw-ring-color: rgb(239 68 68 / var(--tw-ring-opacity));
} }
.hover\:ring-yellow-500:hover{
--tw-ring-opacity: 1;
--tw-ring-color: rgb(234 179 8 / var(--tw-ring-opacity));
}
.hover\:ring-offset-1:hover{ .hover\:ring-offset-1:hover{
--tw-ring-offset-width: 1px; --tw-ring-offset-width: 1px;
} }
@ -4968,6 +5008,10 @@ html {
grid-template-columns: repeat(12, minmax(0, 1fr)); grid-template-columns: repeat(12, minmax(0, 1fr));
} }
.sm\:grid-cols-3{
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.sm\:grid-cols-8{ .sm\:grid-cols-8{
grid-template-columns: repeat(8, minmax(0, 1fr)); grid-template-columns: repeat(8, minmax(0, 1fr));
} }
@ -5071,10 +5115,30 @@ html {
display: none; display: none;
} }
.lg\:w-1\/12{
width: 8.333333%;
}
.lg\:w-11\/12{
width: 91.666667%;
}
.lg\:w-2\/12{
width: 16.666667%;
}
.lg\:w-3\/12{
width: 25%;
}
.lg\:w-4\/12{ .lg\:w-4\/12{
width: 33.333333%; width: 33.333333%;
} }
.lg\:w-5\/12{
width: 41.666667%;
}
.lg\:w-6\/12{ .lg\:w-6\/12{
width: 50%; width: 50%;
} }

View File

@ -1,8 +1,16 @@
info: info:
datum: 24.06.2026 datum: 14.07.2026
release: 2.3.8 release: 2.3.9
changelog: changelog:
- version: 2.3.9
datum: 14.07.2026
changes:
- "Kontakt Neuanlegen/Bearbeiten auf Tailwind-Design der anderen Bereiche angeglichen (Tabs, Icons, Buttons, Kartenrahmen)"
- "Kontakt: Bereich \"Allgemein\" neu in \"Login\" und \"Allgemein\" aufgeteilt"
- "Kontakt: Layout-Fehler behoben, durch den Formularfelder unnötig umgebrochen sind und große Leerflächen entstanden"
- "Kontakt: Feldansicht vereinfacht (weniger Überschriften, einheitlichere Formularzeilen wie im CMS-Bereich)"
- "Kontakt bearbeiten: fehlerhaft doppelt angezeigtes Passwortfeld am Seitenende behoben"
- version: 2.3.8 - version: 2.3.8
datum: 24.06.2026 datum: 24.06.2026
changes: changes: