diff --git a/.docker/images/nginx/conf.d/default.conf b/.docker/images/nginx/conf.d/default.conf index 92b4bd291..9e84e8358 100644 --- a/.docker/images/nginx/conf.d/default.conf +++ b/.docker/images/nginx/conf.d/default.conf @@ -64,10 +64,10 @@ server { try_files $uri @sfFront; } - location /w2p/ { - proxy_pass http://tp:8080/w2p/; - proxy_temp_path /tmp/proxy; - } + # location /w2p/ { + # proxy_pass http://tp:8080/w2p/; + # proxy_temp_path /tmp/proxy; + # } location @sfFront { # Symfony if ($request_method = 'OPTIONS') { diff --git a/src/new/config/reference.php b/src/new/config/reference.php index 577739b43..1875f986e 100644 --- a/src/new/config/reference.php +++ b/src/new/config/reference.php @@ -474,7 +474,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; * datetime?: array{ * default_format?: scalar|null, // Default: "Y-m-d\\TH:i:sP" * default_deserialization_formats?: list, - * default_timezone?: scalar|null, // Default: "Europe/Berlin" + * default_timezone?: scalar|null, // Default: "UTC" * cdata?: scalar|null, // Default: true * }, * array_collection?: array{ @@ -574,7 +574,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; * datetime?: array{ * default_format?: scalar|null, // Default: "Y-m-d\\TH:i:sP" * default_deserialization_formats?: list, - * default_timezone?: scalar|null, // Default: "Europe/Berlin" + * default_timezone?: scalar|null, // Default: "UTC" * cdata?: scalar|null, // Default: true * }, * array_collection?: array{ diff --git a/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/edit/create.html.twig b/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/edit/create.html.twig index 8ba7296dd..0c5af1c02 100755 --- a/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/edit/create.html.twig +++ b/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/edit/create.html.twig @@ -1,226 +1,188 @@ -{% extends 'backend_base.html.twig' %} +{% extends 'backend_tailwind_base.html.twig' %} +{% form_theme form 'tailwind_formtheme.html.twig' %} {% trans_default_domain 'core_voucher_edit' %} -{% block body %} -
-
-
-

- - {{'Voucher'|trans}} > - {{'create'|trans}} -

+{% block header %} +
+
+

+ + + + {{'Voucher'|trans}} {{'create'|trans}} +

+
+ +
+{% endblock %} + +{% block body %} +
+ {{ form_start(form, {attr: {class: ''}}) }} + +
+ {# Vertical Tab Navigation #} + + + {# Tab Content Area #} +
+ {# General Tab #} +
+
{{'General'|trans}}
+ +
+
+ {{ form_row(form.title) }} +
+
+ {{ form_row(form.enable) }} +
+
+ +
+
+ {{ form_row(form.percent) }} +
+
+ {{ form_row(form.value) }} +
+
+ {{ form_row(form.mode) }} +
+
+ +
+
+ {{ form_row(form.more) }} +
+
+ {{ form_row(form.count) }} +
+
+ {{ form_row(form.code) }} +
+
+ +
+
+ {{ form_row(form.zeroPayment) }} +
+
+ {{ form_row(form.zeroShipping) }} +
+
-
- {{'back'|trans}} + + {# Validity Tab #} + + + {# Filter Tab #} + + + {# Custom Tabs #} + {% for customGroup in customGroups %} + + {% endfor %}
-
- {{ form_start(form, { 'attr': {'class': ''}}) }} -
-
-

{{ voucher.title }}

-
-
-
-
- -
-
-
-
-
-
-
- -
- {{ form_widget(form.title) }} -
-
-
-
-
-
{{ form_widget(form.enable) }}
-
-
- -
-
-
-
- -
- {{ form_widget(form.fromDate) }} -
-
-
-
-
- -
- {{ form_widget(form.toDate) }} -
-
-
-
-
-
-
- -
- {{ form_widget(form.percent) }} -
-
-
-
-
- -
- {{ form_widget(form.value) }} -
-
-
-
-
- -
- {{ form_widget(form.mode) }} -
-
-
-
-
-
-
- -
- {{ form_widget(form.more) }} -
-
-
-
-
- -
- {{ form_widget(form.count) }} -
-
-
-
-
- -
- {{ form_widget(form.code) }} -
-
-
-
-
-
-
- -
- {{ form_widget(form.payment) }} -
-
-
-
-
- -
- {{ form_widget(form.shipping) }} -
-
-
-
-
-
-
- -
- {{ form_widget(form.zeroPayment) }} -
-
-
-
-
- -
- {{ form_widget(form.zeroShipping) }} -
-
-
-
-
- -
- {{ form_widget(form.minBasketValue) }} -
-
-
-
-
-
-
-
-
- -
- {{ form_widget(form.productIds) }} -
-
-
-
-
- -
- {{ form_widget(form.productGroupIds) }} -
-
-
-
-
- {% for customGroup in customGroups %} -
- {% for customField in customFields %} - {% if customField.group == customGroup.id and customField.getTemplate %} - {{ include(customField.getTemplate, { 'form': form }) }} - {% endif %} - {% endfor %} -
- {% endfor %} -
-
-
-
-
- -
-
-
-
- {{ form_widget(form.save, {attr: {class: 'btn btn-primary btn-sm'}}) }} -
-
-
-
- {{ form_end(form) }} + {# Save Button outside Card #} +
+ {{ 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]' + } + }) }}
- {{ summernote_mediabundle_init('default') }} + {{ form_end(form) }} +
+ +{{ summernote_mediabundle_init('default') }} {% endblock %} diff --git a/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/edit/delete.html.twig b/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/edit/delete.html.twig index 82bc1f691..ce42df5d7 100755 --- a/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/edit/delete.html.twig +++ b/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/edit/delete.html.twig @@ -1,39 +1,82 @@ -{% extends 'backend_base.html.twig' %} +{% extends 'backend_tailwind_base.html.twig' %} {% trans_default_domain 'core_voucher_delete' %} + +{% block header %} +
+
+

+ + + + {{'Voucher'|trans}} {{'del'|trans}} +

+
+ +
+{% endblock %} + {% block body %} -
-
-
-

- - {{'Voucher'|trans}} > - {{'del'|trans}} +
+ {{ form_start(form, { 'attr': {'class': ''}}) }} +
+ {# Card Header #} +
+
+ + + +

+ {{'DelVoucher'|trans}}?

-
-
-
-
-

{{'DelVoucher'|trans}}?

-
-
- -
{{ voucher.title }}
- - {{ form_start(form, { 'attr': {'class': ''}}) }} -
- -
- {{ form_widget(form.yes, {attr: {class: 'btn btn-lg btn-warning btn-sm'}}) }} -
-
- {{ form_widget(form.no, {attr: {class: 'btn btn-lg btn-primary btn-sm'}}) }} -
+ {# Card Body #} +
+
+
+ + + +

+ {{'This action cannot be undone'|trans}}. +

- {{ form_end(form) }} +
+ +
+
+ {{ voucher.title }} +
+

+ UID: {{ voucher.uid }} +

+
+
+ + {# Card Footer #} +
+
+ {{ 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' + } + }) }} + {{ 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-red-600 hover:bg-red-700 hover:ring-2 hover:ring-red-500 hover:ring-offset-2' + } + }) }}
-{% endblock %} \ No newline at end of file + {{ form_end(form) }} +
+{% endblock %} diff --git a/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/edit/edit.html.twig b/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/edit/edit.html.twig index ddacf87a6..ec136743e 100755 --- a/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/edit/edit.html.twig +++ b/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/edit/edit.html.twig @@ -1,250 +1,188 @@ -{% extends 'backend_base.html.twig' %} +{% extends 'backend_tailwind_base.html.twig' %} +{% form_theme form 'tailwind_formtheme.html.twig' %} {% trans_default_domain 'core_voucher_edit' %} + +{% block header %} +
+
+

+ + + + {{'Voucher'|trans}} {{'edit'|trans}} +

+
+ +
+{% endblock %} + {% block body %} +
+ {{ form_start(form, {attr: {class: ''}}) }} -
-
-
-

- - {{'Voucher'|trans}} > - {{'edit'|trans}} -

-
- +
+ {# Vertical Tab Navigation #} + -
-
- {{ form_start(form, { 'attr': {'class': ''}}) }} -
-
-

{{ voucher.title }}

-
-
-
-
- + {# Tab Content Area #} +
+ {# General Tab #} +
+
{{'General'|trans}}
+ +
+
+ {{ form_row(form.title) }}
-
-
-
-
-
-
- -
- {{ form_widget(form.title) }} -
-
-
-
-
-
{{ form_widget(form.enable) }}
-
-
+
+ {{ form_row(form.enable) }} +
+
-
-
-
-
- -
- {{ form_widget(form.fromDate) }} -
-
-
-
-
- -
- {{ form_widget(form.toDate) }} -
-
-
-
-
-
-
- -
- {{ form_widget(form.percent) }} -
-
-
-
-
- -
- {{ form_widget(form.value) }} -
-
-
-
-
- -
- {{ form_widget(form.mode) }} -
-
-
-
-
-
-
- -
- {{ form_widget(form.more) }} -
-
-
-
-
- -
- {{ form_widget(form.count) }} -
-
-
-
-
- -
- {{ form_widget(form.code) }} -
-
-
-
-
-
-
- -
- {{ form_widget(form.zeroPayment) }} -
-
-
-
-
- -
- {{ form_widget(form.zeroShipping) }} -
-
-
-
-
- -
- {{ form_widget(form.minBasketValue) }} -
-
-
-
-
-
-
- -
- {{ form_widget(form.payment) }} -
-
-
-
-
- -
- {{ form_widget(form.shipping) }} -
-
-
-
-
-
-
-
-
- -
- {{ form_widget(form.productIds) }} -
-
-
-
-
- -
- {{ form_widget(form.productGroupIds) }} -
-
-
-
-
- {% for customGroup in customGroups %} -
- {% for customField in customFields %} - {% if customField.group == customGroup.id and customField.getTemplate %} - {{ include(customField.getTemplate, { 'form': form }) }} - {% endif %} - {% endfor %} -
- {% endfor %} -
+
+
+ {{ form_row(form.percent) }} +
+
+ {{ form_row(form.value) }} +
+
+ {{ form_row(form.mode) }} +
+
+ +
+
+ {{ form_row(form.more) }} +
+
+ {{ form_row(form.count) }} +
+
+ {{ form_row(form.code) }} +
+
+ +
+
+ {{ form_row(form.zeroPayment) }} +
+
+ {{ form_row(form.zeroShipping) }}
-
-
-
-
-
- {{ form_widget(form.save, {attr: {class: 'btn btn-primary btn-sm'}}) }} + {# Validity Tab #} + -
- {{ form_end(form) }} -
- {{ summernote_mediabundle_init('default') }} - -
-
-

{{ 'Changes'|trans }}

-
-
- - - - - - {% for change in changes %} - + {# Filter Tab #} + + + {# Custom Tabs #} + {% for customGroup in customGroups %} + -
{{ 'Date'|trans }}{{ 'Username'|trans }}{{'Changes'|trans}}
{{ change.created|date('H:i:s d.m.Y') }}{{ change.username }} - {% for key,set in change.changeset %} - {% if set[1] is not iterable %} - {{key}} {{ set[0]}}{% if set[1] is null %}0{% else %}{{ set[1] }}{% endif %}
- {% endif %} - {% endfor %} -
+
+ {% endfor %}
+ {# Save Button outside Card #} +
+ {{ 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]' + } + }) }} +
+ + {{ form_end(form) }} +
+ +{{ summernote_mediabundle_init('default') }} + {% endblock %} diff --git a/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/list/index.html.twig b/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/list/index.html.twig index 40da37909..d235d699e 100755 --- a/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/list/index.html.twig +++ b/src/new/src/PSC/Shop/VoucherBundle/Resources/views/backend/list/index.html.twig @@ -1,75 +1,145 @@ -{% extends 'backend_base.html.twig' %} +{% extends 'backend_tailwind_base.html.twig' %} {% trans_default_domain 'core_voucher_list' %} -{% block body %} -
-
-
-

- - {{'Voucher'|trans}} > - {{'List'|trans}} -

-
+ +{% block header %} +
+
+

+ + + + {{'Voucher'|trans}} {{'List'|trans}} +

-
-
- -
-
- - - - - - - - - - - - - - - - - - - {% for voucher in pagination %} - - - - - - - - - - - - - - - {% endfor %} - -
{{ knp_pagination_sortable(pagination, 'Uid'|trans, 'voucher.uid') }}{{ knp_pagination_sortable(pagination, 'Createdat'|trans, 'product.createdAt') }}{{ knp_pagination_sortable(pagination, 'Updatedat'|trans, 'product.updatedAt') }}{{ knp_pagination_sortable(pagination, 'active'|trans, 'voucher.enable') }}{{ knp_pagination_sortable(pagination, 'Name'|trans, 'voucher.title') }}{{ knp_pagination_sortable(pagination, 'from'|trans, 'voucher.fromDate') }}{{ knp_pagination_sortable(pagination, 'to'|trans, 'voucher.toDate') }}{{ knp_pagination_sortable(pagination, 'Percent'|trans, 'voucher.percent') }}{{ knp_pagination_sortable(pagination, 'Value'|trans, 'voucher.value') }}{{'Numbertogenerate'|trans}}{{'Numbergenerated'|trans}}
{{ voucher.uid }}{{ voucher.createdAt|date('H:i d.m.Y') }}{{ voucher.updatedAt|date('H:i d.m.Y') }}{% if voucher.enable %}{{'yes'|trans}}{% else %}{{'no'|trans}}{% endif %}{{ voucher.title }}{{ voucher.fromDate|date('d.m.Y') }}{{ voucher.toDate|date('d.m.Y') }}{% if voucher.percent %}{{'yes'|trans}}{% else %}{{'no'|trans}}{% endif %}{{ voucher.value|number_format(2, ',', '.') }}{% if voucher.more %}Keine Individuellen Codes{% else %}{{ voucher.count }}{% endif %}{% if voucher.more %}Keine Individuellen Codes{% else %}{{ voucher.voucherItems|length }}{% endif %} - {{'Export'|trans}} - {{'Generate'|trans}} - - -
- -
+
{% endblock %} + +{% block body %} +
+
+
+ + + + + + + + + + + + + + + + + + + {% for voucher in pagination %} + + + + + + + + + + + + + + + {% endfor %} + +
+ {{ knp_pagination_sortable(pagination, 'Uid'|trans, 'voucher.uid') }} + + {{ knp_pagination_sortable(pagination, 'Createdat'|trans, 'product.createdAt') }} + + {{ knp_pagination_sortable(pagination, 'Updatedat'|trans, 'product.updatedAt') }} + + {{ knp_pagination_sortable(pagination, 'active'|trans, 'voucher.enable') }} + + {{ knp_pagination_sortable(pagination, 'Name'|trans, 'voucher.title') }} + + {{ knp_pagination_sortable(pagination, 'from'|trans, 'voucher.fromDate') }} + + {{ knp_pagination_sortable(pagination, 'to'|trans, 'voucher.toDate') }} + + {{ knp_pagination_sortable(pagination, 'Percent'|trans, 'voucher.percent') }} + + {{ knp_pagination_sortable(pagination, 'Value'|trans, 'voucher.value') }} + + {{'Numbertogenerate'|trans}} + + {{'Numbergenerated'|trans}} + + Aktionen +
+ + + + + {{ voucher.uid }} + + {{ voucher.createdAt|date('H:i d.m.Y') }}{{ voucher.updatedAt|date('H:i d.m.Y') }} + {% if voucher.enable %} + {{'yes'|trans}} + {% else %} + {{'no'|trans}} + {% endif %} + {{ voucher.title }}{{ voucher.fromDate|date('d.m.Y') }}{{ voucher.toDate|date('d.m.Y') }} + {% if voucher.percent %} + {{'yes'|trans}} + {% else %} + {{'no'|trans}} + {% endif %} + {{ voucher.value|number_format(2, ',', '.') }}{% if voucher.more %}Keine Individuellen Codes{% else %}{{ voucher.count }}{% endif %}{% if voucher.more %}Keine Individuellen Codes{% else %}{{ voucher.voucherItems|length }}{% endif %} +
+ {# Export - BLAU #} + + + + + + {# Generate - GELB #} + + + + + + {# Bearbeiten - GRÜN #} + + + + + + {# Löschen - ROT #} + + + + + +
+
+
+ +
+ {{ knp_pagination_render(pagination, 'tailwind_pagination.html.twig', {}, { + 'sortableTemplate': 'tailwind_sortable.html.twig' + }) }} +
+
+
+{% endblock %} diff --git a/src/new/var/plugins/Custom/PSC/Gutschein/Entity/GutscheinCode.php b/src/new/var/plugins/Custom/PSC/Gutschein/Entity/GutscheinCode.php new file mode 100644 index 000000000..8d3a2257a --- /dev/null +++ b/src/new/var/plugins/Custom/PSC/Gutschein/Entity/GutscheinCode.php @@ -0,0 +1,150 @@ +id; + } + + public function getCode(): string + { + return $this->code; + } + + public function setCode(string $code): void + { + $this->code = $code; + } + + public function getOrderPositionId(): int + { + return $this->orderPositionId; + } + + public function setOrderPositionId(int $orderPositionId): void + { + $this->orderPositionId = $orderPositionId; + } + + public function getAmount(): float + { + return $this->amount; + } + + public function setAmount(float $amount): void + { + $this->amount = $amount; + } + + public function getExpirationDate(): \DateTime + { + return $this->expirationDate; + } + + public function setExpirationDate(\DateTime $expirationDate): void + { + $this->expirationDate = $expirationDate; + } + + public function getCreatedAt(): \DateTime + { + return $this->createdAt; + } + + public function setCreatedAt(\DateTime $createdAt): void + { + $this->createdAt = $createdAt; + } + + public function isUsed(): bool + { + return $this->used; + } + + public function setUsed(bool $used): void + { + $this->used = $used; + } + + public function getUsedAt(): ?\DateTime + { + return $this->usedAt; + } + + public function setUsedAt(?\DateTime $usedAt): void + { + $this->usedAt = $usedAt; + } + + public function getUsedInOrderId(): ?int + { + return $this->usedInOrderId; + } + + public function setUsedInOrderId(?int $usedInOrderId): void + { + $this->usedInOrderId = $usedInOrderId; + } + + public function isValid(): bool + { + return !$this->used && $this->expirationDate > new \DateTime(); + } +} diff --git a/src/new/var/plugins/Custom/PSC/Gutschein/Form/Field/Calc.php b/src/new/var/plugins/Custom/PSC/Gutschein/Form/Field/Calc.php new file mode 100644 index 000000000..25ea5dec7 --- /dev/null +++ b/src/new/var/plugins/Custom/PSC/Gutschein/Form/Field/Calc.php @@ -0,0 +1,87 @@ +add('minAmount', MoneyType::class, [ + 'required' => false, + 'label' => 'Minimaler Gutscheinwert', + 'data' => 10.00, + ])->add('maxAmount', MoneyType::class, [ + 'required' => false, + 'label' => 'Maximaler Gutscheinwert', + 'data' => 500.00, + ])->add('defaultAmount', MoneyType::class, [ + 'required' => false, + 'label' => 'Voreingestellter Wert', + 'data' => 50.00, + ])->add('validityMonths', IntegerType::class, [ + 'required' => false, + 'label' => 'Gültigkeit (Monate)', + 'data' => 12, + ]); + + if ($product) { + $builder->get('defaultAmount')->setData($product->gutschein['defaultAmount'] ?? null); + $builder->get('minAmount')->setData($product->gutschein['minAmount'] ?? null); + $builder->get('maxAmount')->setData($product->gutschein['maxAmount'] ?? null); + $builder->get('validityMonths')->setData($product->gutschein['validityMonths'] ?? null); + } + return $builder; + } + + public function getGroup() + { + return \Plugin\Custom\PSC\Gutschein\Form\Group\Calc::GROUP_ID; + } + + public function formPostSetData(FormEvent $event) + { + } + + public function formPostSubmit(FormEvent $event) + { + } + + public function formPreSetData(FormEvent $event) + { + } + + public function formSubmit(FormEvent $event) + { + } +} diff --git a/src/new/var/plugins/Custom/PSC/Gutschein/Form/Group/Calc.php b/src/new/var/plugins/Custom/PSC/Gutschein/Form/Group/Calc.php new file mode 100644 index 000000000..3a64e6c2d --- /dev/null +++ b/src/new/var/plugins/Custom/PSC/Gutschein/Form/Group/Calc.php @@ -0,0 +1,26 @@ +title = 'Gutschein-Einstellungen'; + } + + public function getModule() + { + return Field::Product; + } + + public function getId() + { + return self::GROUP_ID; + } +} diff --git a/src/new/var/plugins/Custom/PSC/Gutschein/Model/ProductSpecialObject.php b/src/new/var/plugins/Custom/PSC/Gutschein/Model/ProductSpecialObject.php new file mode 100644 index 000000000..b6622c932 --- /dev/null +++ b/src/new/var/plugins/Custom/PSC/Gutschein/Model/ProductSpecialObject.php @@ -0,0 +1,172 @@ + $this->params, + 'voucherAmount' => $this->voucherAmount, + 'recipientName' => $this->recipientName, + 'greetingMessage' => $this->greetingMessage, + 'deliveryMethod' => $this->deliveryMethod, + 'voucherCode' => $this->voucherCode, + 'expirationDate' => $this->expirationDate?->format('Y-m-d H:i:s'), + 'validityMonths' => $this->validityMonths, + ]; + } + + // Getters and Setters + public function getTaxClass(): int + { + return $this->taxClass; + } + + public function setTaxClass(int $taxClass): void + { + $this->taxClass = $taxClass; + } + + public function getParams(): array + { + return $this->params; + } + + public function setParams(array $params): void + { + $this->params = $params; + } + + public function getMinAmount(): float + { + return $this->minAmount; + } + + public function setMinAmount(float $minAmount): void + { + $this->minAmount = $minAmount; + } + + public function getMaxAmount(): float + { + return $this->maxAmount; + } + + public function setMaxAmount(float $maxAmount): void + { + $this->maxAmount = $maxAmount; + } + + public function getDefaultAmount(): ?float + { + return $this->defaultAmount; + } + + public function setDefaultAmount(?float $defaultAmount): void + { + $this->defaultAmount = $defaultAmount; + } + + public function getValidityMonths(): int + { + return $this->validityMonths; + } + + public function setValidityMonths(int $validityMonths): void + { + $this->validityMonths = $validityMonths; + } + + public function getVoucherAmount(): float + { + return $this->voucherAmount; + } + + public function setVoucherAmount(float $voucherAmount): void + { + $this->voucherAmount = $voucherAmount; + } + + public function getRecipientName(): string + { + return $this->recipientName; + } + + public function setRecipientName(string $recipientName): void + { + $this->recipientName = $recipientName; + } + + public function getGreetingMessage(): string + { + return $this->greetingMessage; + } + + public function setGreetingMessage(string $greetingMessage): void + { + $this->greetingMessage = $greetingMessage; + } + + public function getDeliveryMethod(): string + { + return $this->deliveryMethod; + } + + public function setDeliveryMethod(string $deliveryMethod): void + { + $this->deliveryMethod = $deliveryMethod; + } + + public function getVoucherCode(): string + { + return $this->voucherCode; + } + + public function setVoucherCode(string $voucherCode): void + { + $this->voucherCode = $voucherCode; + } + + public function getExpirationDate(): ?\DateTime + { + return $this->expirationDate; + } + + public function setExpirationDate(?\DateTime $expirationDate): void + { + $this->expirationDate = $expirationDate; + } +} diff --git a/src/new/var/plugins/Custom/PSC/Gutschein/Plugin.php b/src/new/var/plugins/Custom/PSC/Gutschein/Plugin.php new file mode 100644 index 000000000..0042c09a6 --- /dev/null +++ b/src/new/var/plugins/Custom/PSC/Gutschein/Plugin.php @@ -0,0 +1,40 @@ +product = $product; + $this->process(); + } + + public function getPrice(): Price + { + /** @var ProductSpecialObject $specProd */ + $specProd = $this->product->getSpecialProductTypeObject(); + + // CRITICAL: Voucher amount is customer-defined, not from product entity + $priceObj = Money::ofMinor($this->voucherAmount * 100, 'EUR'); + + $price = new Price(); + $price->setNet($priceObj->getMinorAmount()->toInt()); + $price->setVat( + $priceObj + ->toRational() + ->dividedBy(100) + ->multipliedBy($specProd->getTaxClass() / 100) + ->to($priceObj->getContext(), RoundingMode::UP) + ->getMinorAmount() + ->toInt(), + ); + $price->setGross($price->getNet() + $price->getVat()); + $price->setCount($this->count); + $price->setAllNet($price->getNet() * $this->count); + $price->setAllVat($price->getVat() * $this->count); + $price->setAllGross($price->getGross() * $this->count); + $price->tax = new Tax($specProd->getTaxClass(), $price->getAllNet(), $price->getAllVat(), TaxEnum::POSITION); + + return $price; + } + + public function getJsonForm(): array + { + /** @var ProductSpecialObject $specProd */ + $specProd = $this->product->getSpecialProductTypeObject(); + + return [ + 'title' => $this->product->getTitle(), + 'type' => 'object', + 'properties' => [ + 'voucherAmount' => [ + 'type' => 'number', + 'title' => 'Gutscheinwert (€)', + 'minimum' => $specProd->getMinAmount(), + 'maximum' => $specProd->getMaxAmount(), + 'default' => $specProd->getDefaultAmount() ?? 50.00, + ], + 'recipientName' => [ + 'type' => 'string', + 'title' => 'Name des Empfängers', + 'maxLength' => 100, + ], + 'greetingMessage' => [ + 'type' => 'string', + 'title' => 'Grußtext (optional)', + 'maxLength' => 500, + ], + 'deliveryMethod' => [ + 'type' => 'string', + 'title' => 'Versandart', + 'enum' => ['digital', 'physical'], + 'enumNames' => ['Digital (E-Mail)', 'Gedruckt (Postversand)'], + 'default' => 'digital', + ], + 'count' => [ + 'type' => 'integer', + 'title' => 'Anzahl', + 'minimum' => 1, + 'default' => 1, + ], + ], + 'required' => ['voucherAmount', 'recipientName', 'deliveryMethod'], + ]; + } + + public function setParams(array $params): void + { + if (isset($params['voucherAmount'])) { + $this->voucherAmount = (float) $params['voucherAmount']; + } + if (isset($params['recipientName'])) { + $this->recipientName = $params['recipientName']; + } + if (isset($params['greetingMessage'])) { + $this->greetingMessage = $params['greetingMessage']; + } + if (isset($params['deliveryMethod'])) { + $this->deliveryMethod = $params['deliveryMethod']; + } + if (isset($params['count'])) { + $this->count = (int) $params['count']; + } + } + + public function getCount(): int + { + return $this->count; + } + + public function calcPriceForOrderPosition(Position $position): void + { + // Generate unique voucher code for this order position + $voucherCode = $this->codeGenerator->generate(); + + /** @var ProductSpecialObject $specProd */ + $specProd = $position->getProduct()->getSpecialProductTypeObject(); + $specProd->setVoucherCode($voucherCode); + $specProd->setVoucherAmount($this->voucherAmount); + $specProd->setRecipientName($this->recipientName); + $specProd->setGreetingMessage($this->greetingMessage); + $specProd->setDeliveryMethod($this->deliveryMethod); + + // Calculate expiration date + $validityMonths = $specProd->getValidityMonths() ?? 12; + $expirationDate = new \DateTime(); + $expirationDate->modify("+{$validityMonths} months"); + $specProd->setExpirationDate($expirationDate); + + $position->setPrice($this->getPrice()); + } + + public function getProductTransformer(): IProductTransformer + { + return new \Plugin\Custom\PSC\Gutschein\Transformer\Product(); + } + + public function getUiJsonForm(): array + { + /** @var ProductSpecialObject $specProd */ + $specProd = $this->product->getSpecialProductTypeObject(); + + $minAmount = $specProd->getMinAmount(); + $maxAmount = $specProd->getMaxAmount(); + + return [ + 'ui:submitButtonOptions' => [ + 'submitText' => 'In den Warenkorb', + 'norender' => true, + 'props' => [ + 'disabled' => false, + 'className' => 'btn btn-primary btn-lg', + ], + ], + 'voucherAmount' => [ + 'ui:widget' => 'updown', + 'ui:help' => "Wählen Sie einen Betrag zwischen {$minAmount}€ und {$maxAmount}€", + ], + 'greetingMessage' => [ + 'ui:widget' => 'textarea', + 'ui:options' => [ + 'rows' => 5, + ], + ], + ]; + } + + private function process(): void + { + // Load existing params from product if available + if (!empty($this->product->getSpecialProductTypeObject()->getParams())) { + $params = $this->product->getSpecialProductTypeObject()->getParams(); + $this->setParams($params); + } + } +} diff --git a/src/new/var/plugins/Custom/PSC/Gutschein/Repository/GutscheinCodeRepository.php b/src/new/var/plugins/Custom/PSC/Gutschein/Repository/GutscheinCodeRepository.php new file mode 100644 index 000000000..bac81580c --- /dev/null +++ b/src/new/var/plugins/Custom/PSC/Gutschein/Repository/GutscheinCodeRepository.php @@ -0,0 +1,61 @@ +createQueryBuilder('gc'); + + return $qb + ->where('gc.code = :code') + ->andWhere('gc.used = :used') + ->andWhere('gc.expirationDate > :now') + ->setParameter('code', $code) + ->setParameter('used', false) + ->setParameter('now', new \DateTime()) + ->getQuery() + ->getOneOrNullResult(); + } + + public function findByOrderPosition(int $orderPositionId): array + { + return $this->findBy(['orderPositionId' => $orderPositionId]); + } + + public function getUsageStats(): array + { + $qb = $this->createQueryBuilder('gc'); + + $total = (clone $qb) + ->select('COUNT(gc.id)') + ->getQuery() + ->getSingleScalarResult(); + + $used = (clone $qb) + ->select('COUNT(gc.id)') + ->where('gc.used = :used') + ->setParameter('used', true) + ->getQuery() + ->getSingleScalarResult(); + + $expired = (clone $qb) + ->select('COUNT(gc.id)') + ->where('gc.expirationDate < :now') + ->andWhere('gc.used = :used') + ->setParameter('now', new \DateTime()) + ->setParameter('used', false) + ->getQuery() + ->getSingleScalarResult(); + + return [ + 'total' => $total, + 'used' => $used, + 'expired' => $expired, + ]; + } +} diff --git a/src/new/var/plugins/Custom/PSC/Gutschein/Resources/config/services.yml b/src/new/var/plugins/Custom/PSC/Gutschein/Resources/config/services.yml new file mode 100644 index 000000000..0ebbb98a6 --- /dev/null +++ b/src/new/var/plugins/Custom/PSC/Gutschein/Resources/config/services.yml @@ -0,0 +1,19 @@ +services: + _defaults: + autowire: true + autoconfigure: true + + Plugin\Custom\PSC\Gutschein\: + resource: '../../*/*' + + Plugin\Custom\PSC\Gutschein\Service\ProductType: + tags: + - { name: psc.product.type } + + Plugin\Custom\PSC\Gutschein\Form\Group\Calc: + tags: + - { name: psc.backend.custom.groups, productType: 9 } + + Plugin\Custom\PSC\Gutschein\Form\Field\Calc: + tags: + - { name: psc.backend.custom.fields, productType: 9 } diff --git a/src/new/var/plugins/Custom/PSC/Gutschein/Resources/views/form/field/calc.html.twig b/src/new/var/plugins/Custom/PSC/Gutschein/Resources/views/form/field/calc.html.twig new file mode 100644 index 000000000..e972b5cf6 --- /dev/null +++ b/src/new/var/plugins/Custom/PSC/Gutschein/Resources/views/form/field/calc.html.twig @@ -0,0 +1,44 @@ +
+
+
Gutschein-Konfiguration
+
+
+
+
+
+ {{ form_label(form.gutschein.validityMonths) }} + {{ form_widget(form.gutschein.validityMonths) }} + Gültigkeitsdauer ab Kaufdatum +
+
+
+ +
+
+
+ {{ form_label(form.gutschein.minAmount) }} + {{ form_widget(form.gutschein.minAmount) }} + Mindestbetrag +
+
+
+
+ {{ form_label(form.gutschein.defaultAmount) }} + {{ form_widget(form.gutschein.defaultAmount) }} + Vorauswahl +
+
+
+
+ {{ form_label(form.gutschein.maxAmount) }} + {{ form_widget(form.gutschein.maxAmount) }} + Maximalbetrag +
+
+
+ +
+ Hinweis: Kunden können beim Kauf einen beliebigen Betrag zwischen Minimal- und Maximalbetrag wählen. +
+
+
diff --git a/src/new/var/plugins/Custom/PSC/Gutschein/Service/CodeGenerator.php b/src/new/var/plugins/Custom/PSC/Gutschein/Service/CodeGenerator.php new file mode 100644 index 000000000..e300e9176 --- /dev/null +++ b/src/new/var/plugins/Custom/PSC/Gutschein/Service/CodeGenerator.php @@ -0,0 +1,83 @@ +generateCode(); + $exists = $this->codeExists($code); + $attempts++; + + if ($attempts >= self::MAX_ATTEMPTS) { + throw new \RuntimeException('Could not generate unique voucher code after ' . self::MAX_ATTEMPTS . ' attempts'); + } + } while ($exists); + + return $code; + } + + private function generateCode(): string + { + // Format: GS-XXXX-XXXX-XXXX-XXXX + $segments = []; + for ($i = 0; $i < 4; $i++) { + $segments[] = $this->randomSegment(4); + } + + return self::CODE_PREFIX . '-' . implode('-', $segments); + } + + private function randomSegment(int $length): string + { + $characters = '0123456789ABCDEFGHJKLMNPQRSTUVWXYZ'; // Exclude I, O to avoid confusion + $segment = ''; + + for ($i = 0; $i < $length; $i++) { + $segment .= $characters[random_int(0, strlen($characters) - 1)]; + } + + return $segment; + } + + private function codeExists(string $code): bool + { + $existing = $this->entityManager + ->getRepository(GutscheinCode::class) + ->findOneBy(['code' => $code]); + + return $existing !== null; + } + + public function saveCode(string $code, int $orderPositionId, float $amount, \DateTime $expirationDate): GutscheinCode + { + $gutscheinCode = new GutscheinCode(); + $gutscheinCode->setCode($code); + $gutscheinCode->setOrderPositionId($orderPositionId); + $gutscheinCode->setAmount($amount); + $gutscheinCode->setExpirationDate($expirationDate); + $gutscheinCode->setCreatedAt(new \DateTime()); + $gutscheinCode->setUsed(false); + + $this->entityManager->persist($gutscheinCode); + $this->entityManager->flush(); + + return $gutscheinCode; + } +} diff --git a/src/new/var/plugins/Custom/PSC/Gutschein/Service/ProductType.php b/src/new/var/plugins/Custom/PSC/Gutschein/Service/ProductType.php new file mode 100644 index 000000000..7d12d85d3 --- /dev/null +++ b/src/new/var/plugins/Custom/PSC/Gutschein/Service/ProductType.php @@ -0,0 +1,47 @@ +productTransformer = $positionTransformer; + $this->producer = $producer; + } + + public function getId() + { + return 9; // NEW UNIQUE ID + } + + public function getName() + { + return 'Gutscheinprodukt'; + } + + public function getPositionProductTransformer(): IPositionTransformer + { + return $this->productTransformer; + } + + public function getProducer(): IProducer + { + return $this->producer; + } + + public function getProductTypeObject(): IProductTypeObject + { + return new ProductSpecialObject(); + } +} diff --git a/src/new/var/plugins/Custom/PSC/Gutschein/Transformer/Position.php b/src/new/var/plugins/Custom/PSC/Gutschein/Transformer/Position.php new file mode 100644 index 000000000..dd93671fe --- /dev/null +++ b/src/new/var/plugins/Custom/PSC/Gutschein/Transformer/Position.php @@ -0,0 +1,56 @@ +getSpecialProductTypeObject(); + + if (isset($data['params'])) { + $obj->setParams($data['params']); + } + if (isset($data['voucherAmount'])) { + $obj->setVoucherAmount($data['voucherAmount']); + } + if (isset($data['recipientName'])) { + $obj->setRecipientName($data['recipientName']); + } + if (isset($data['greetingMessage'])) { + $obj->setGreetingMessage($data['greetingMessage']); + } + if (isset($data['deliveryMethod'])) { + $obj->setDeliveryMethod($data['deliveryMethod']); + } + if (isset($data['voucherCode'])) { + $obj->setVoucherCode($data['voucherCode']); + } + if (isset($data['expirationDate'])) { + $obj->setExpirationDate(new \DateTime($data['expirationDate'])); + } + if (isset($data['validityMonths'])) { + $obj->setValidityMonths($data['validityMonths']); + } + + $position->getProduct()->setSpecialProductTypeObject($obj); + } + + public function toDb( + \PSC\Shop\OrderBundle\Model\Order\Position $position, + Orderpos $posEntity, + \PSC\Shop\EntityBundle\Document\Position $posDoc + ) { + // Position data is stored via getPositionData() in ProductSpecialObject + // No additional transformation needed here + } +} diff --git a/src/new/var/plugins/Custom/PSC/Gutschein/Transformer/Product.php b/src/new/var/plugins/Custom/PSC/Gutschein/Transformer/Product.php new file mode 100644 index 000000000..bc5052b76 --- /dev/null +++ b/src/new/var/plugins/Custom/PSC/Gutschein/Transformer/Product.php @@ -0,0 +1,54 @@ +getSpecialProductTypeObject() == null) { + $productModel->setSpecialProductTypeObject(new ProductSpecialObject()); + } + + /** @var ProductSpecialObject $prodSpec */ + $prodSpec = $productModel->getSpecialProductTypeObject(); + + // Load backend configuration from product entity + $prodSpec->setTaxClass($productEntity->getMwert() * 100); + + // Load custom fields from MongoDB document (if stored there) + if ($productDoc->getCustom1()) { + $prodSpec->setMinAmount((float)$productDoc->getCustom1()); + } + if ($productDoc->getCustom2()) { + $prodSpec->setMaxAmount((float)$productDoc->getCustom2()); + } + if ($productDoc->getCustom3()) { + $prodSpec->setDefaultAmount((float)$productDoc->getCustom3()); + } + if ($productDoc->getCustom4()) { + $prodSpec->setValidityMonths((int)$productDoc->getCustom4()); + } + } + + public function toDb( + \PSC\Shop\ProductBundle\Model\Product $productModel, + \PSC\Shop\EntityBundle\Entity\Product $productEntity, + \PSC\Shop\EntityBundle\Document\Product $productDoc + ): void { + /** @var ProductSpecialObject $prodSpec */ + $prodSpec = $productModel->getSpecialProductTypeObject(); + + // Save configuration to MongoDB custom fields + $productDoc->setCustom1((string)$prodSpec->getMinAmount()); + $productDoc->setCustom2((string)$prodSpec->getMaxAmount()); + $productDoc->setCustom3((string)$prodSpec->getDefaultAmount()); + $productDoc->setCustom4((string)$prodSpec->getValidityMonths()); + } +} diff --git a/src/new/var/plugins/Custom/PSC/LaufkartenLayouter/Resources/views/frontend/designer/start.html.twig b/src/new/var/plugins/Custom/PSC/LaufkartenLayouter/Resources/views/frontend/designer/start.html.twig index fe287ce25..a6067477d 100644 --- a/src/new/var/plugins/Custom/PSC/LaufkartenLayouter/Resources/views/frontend/designer/start.html.twig +++ b/src/new/var/plugins/Custom/PSC/LaufkartenLayouter/Resources/views/frontend/designer/start.html.twig @@ -67,6 +67,7 @@
+ Abbrechen & Zurück
@@ -799,7 +800,19 @@ title="Berechneter Wert: ${tabInfo}" onchange="updateTabNumber(${index}, this.value)" /> - + + + + ${ocrPreviewHtml} diff --git a/src/new/var/plugins/Custom/PSC/Pitchprint/Form/Field/ShopSettings.php b/src/new/var/plugins/Custom/PSC/Pitchprint/Form/Field/ShopSettings.php index 4a816b4b9..3289c4678 100755 --- a/src/new/var/plugins/Custom/PSC/Pitchprint/Form/Field/ShopSettings.php +++ b/src/new/var/plugins/Custom/PSC/Pitchprint/Form/Field/ShopSettings.php @@ -1,81 +1,94 @@ -getData(); - $event->getForm()->get('Pitchprint')->get('publicKey')->setData($data->getPluginSettingModule('pitchprint', 'publicKey')); - $event->getForm()->get('Pitchprint')->get('secretKey')->setData($data->getPluginSettingModule('pitchprint', 'secretKey')); - } - - public function buildForm(FormBuilderInterface $builder, array $options) - { - $builder->add('publicKey', TextType::class, array( - 'label' => 'API Key', - 'required' => false, - 'mapped'=> false - )); - $builder->add('secretKey', TextType::class, array( - 'label' => 'API Secret Key', - 'required' => false, - 'mapped'=> false - )); - - return $builder; - } - - public function getGroup() - { - return Pitchprint::GROUP_ID; - } - - public function formPreSubmit(FormEvent $event) - { - // TODO: Implement formPreSubmit() method. - } - - public function formPreSetData(FormEvent $event) - { - } + } + + public function formPostSetData(FormEvent $event) + { + /** @var Shop $data */ + $data = $event->getData(); + $event + ->getForm() + ->get('Pitchprint') + ->get('publicKey') + ->setData($data->getPluginSettingModule('pitchprint', 'publicKey')); + $event + ->getForm() + ->get('Pitchprint') + ->get('secretKey') + ->setData($data->getPluginSettingModule('pitchprint', 'secretKey')); + } + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->add('publicKey', TextType::class, array( + 'label' => 'API Key', + 'required' => false, + 'mapped' => false, + )); + $builder->add('secretKey', TextType::class, array( + 'label' => 'API Secret Key', + 'required' => false, + 'mapped' => false, + )); + + return $builder; + } + + public function getGroup() + { + return Pitchprint::GROUP_ID; + } + + public function formPreSubmit(FormEvent $event) + { + // TODO: Implement formPreSubmit() method. + } + + public function formPreSetData(FormEvent $event) + { + } public function formSubmit(FormEvent $event) - { - /** @var Shop $data */ - $data = $event->getData(); - $data->setPluginSettingModule('pitchprint', 'publicKey', $event->getForm()->get('Pitchprint')->get('publicKey')->getData()); - $data->setPluginSettingModule('pitchprint', 'secretKey', $event->getForm()->get('Pitchprint')->get('secretKey')->getData()); - + { + /** @var Shop $data */ + $data = $event->getData(); + $data->setPluginSettingModule( + 'pitchprint', + 'publicKey', + $event->getForm()->get('Pitchprint')->get('publicKey')->getData(), + ); + $data->setPluginSettingModule( + 'pitchprint', + 'secretKey', + $event->getForm()->get('Pitchprint')->get('secretKey')->getData(), + ); } -} +} diff --git a/src/new/var/plugins/System/PSC/Invoice/Controller/Backend/IndexController.php b/src/new/var/plugins/System/PSC/Invoice/Controller/Backend/IndexController.php index c7660b8b9..929ebf45b 100755 --- a/src/new/var/plugins/System/PSC/Invoice/Controller/Backend/IndexController.php +++ b/src/new/var/plugins/System/PSC/Invoice/Controller/Backend/IndexController.php @@ -1,20 +1,22 @@ $jwtManager->create($this->getUser())); } -} \ No newline at end of file +} + diff --git a/src/new/var/plugins/System/PSC/Invoice/Controller/Backend/OrderController.php b/src/new/var/plugins/System/PSC/Invoice/Controller/Backend/OrderController.php index b1a1d5791..77ad944cd 100755 --- a/src/new/var/plugins/System/PSC/Invoice/Controller/Backend/OrderController.php +++ b/src/new/var/plugins/System/PSC/Invoice/Controller/Backend/OrderController.php @@ -9,7 +9,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; class OrderController extends AbstractController { #[Template('@PluginSystemPSCInvoice/backend/order/index.html.twig')] - public function indexAction(null|\PSC\Shop\EntityBundle\Entity\Order $order, null|Order $orderDoc) + public function indexAction(?\PSC\Shop\EntityBundle\Entity\Order $order, ?Order $orderDoc) { return ['uuid' => $order ? $order->getUuid() : false]; } diff --git a/src/new/var/tailwind/backend.built.css b/src/new/var/tailwind/backend.built.css index 72a4446ea..06538111a 100644 --- a/src/new/var/tailwind/backend.built.css +++ b/src/new/var/tailwind/backend.built.css @@ -922,10 +922,6 @@ html { grid-column: span 2 / span 2; } -.col-span-3{ - grid-column: span 3 / span 3; -} - .col-span-4{ grid-column: span 4 / span 4; } @@ -1863,6 +1859,11 @@ html { background-color: rgb(239 68 68 / var(--tw-bg-opacity)); } +.bg-red-600{ + --tw-bg-opacity: 1; + background-color: rgb(220 38 38 / var(--tw-bg-opacity)); +} + .bg-slate-100{ --tw-bg-opacity: 1; background-color: rgb(241 245 249 / var(--tw-bg-opacity)); @@ -2781,6 +2782,11 @@ html { background-color: rgb(220 38 38 / var(--tw-bg-opacity)); } +.hover\:bg-red-700:hover{ + --tw-bg-opacity: 1; + background-color: rgb(185 28 28 / var(--tw-bg-opacity)); +} + .hover\:bg-white:hover{ --tw-bg-opacity: 1; background-color: rgb(255 255 255 / var(--tw-bg-opacity)); @@ -2831,6 +2837,11 @@ html { color: rgb(255 255 255 / var(--tw-text-opacity)); } +.hover\:text-yellow-700:hover{ + --tw-text-opacity: 1; + color: rgb(161 98 7 / var(--tw-text-opacity)); +} + .hover\:underline:hover{ text-decoration-line: underline; } @@ -3190,6 +3201,11 @@ html { color: rgb(255 255 255 / var(--tw-text-opacity)); } +:is(.dark .dark\:text-yellow-500){ + --tw-text-opacity: 1; + color: rgb(234 179 8 / var(--tw-text-opacity)); +} + :is(.dark .dark\:placeholder-gray-400)::-moz-placeholder{ --tw-placeholder-opacity: 1; color: rgb(156 163 175 / var(--tw-placeholder-opacity)); @@ -3247,6 +3263,11 @@ html { background-color: rgb(88 25 19 / var(--tw-bg-opacity)); } +:is(.dark .dark\:hover\:text-blue-400:hover){ + --tw-text-opacity: 1; + color: rgb(96 165 250 / var(--tw-text-opacity)); +} + :is(.dark .dark\:hover\:text-blue-500:hover){ --tw-text-opacity: 1; color: rgb(59 130 246 / var(--tw-text-opacity)); @@ -3277,6 +3298,11 @@ html { color: rgb(255 255 255 / var(--tw-text-opacity)); } +:is(.dark .dark\:hover\:text-yellow-400:hover){ + --tw-text-opacity: 1; + color: rgb(250 204 21 / var(--tw-text-opacity)); +} + :is(.dark .dark\:focus\:border-blue-500:focus){ --tw-border-opacity: 1; border-color: rgb(59 130 246 / var(--tw-border-opacity)); @@ -3407,6 +3433,10 @@ html { width: 41.666667%; } + .md\:w-9\/12{ + width: 75%; + } + .md\:w-fit{ width: -moz-fit-content; width: fit-content; @@ -3484,6 +3514,10 @@ html { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .lg\:grid-cols-3{ + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + .lg\:gap-8{ gap: 2rem; }