Change channel select button

This commit is contained in:
Michał Pysiak 2024-07-02 08:59:11 +02:00 committed by Grzegorz Sadowski
parent 490b292b3d
commit eab7b8d0b5
13 changed files with 162 additions and 23 deletions

View file

@ -47,16 +47,18 @@ Feature: Statistics for a specific channel
And there should be total sales of "$5,241.00"
And the average order value should be "$1,310.25"
@no-api @ui
@no-api @ui @mink:chromedriver
Scenario: Seeing recent orders in a specific channel
Given 3 new customers have placed 4 orders for total of "$8,566.00" mostly "Onion" product
And 2 more new customers have placed 2 orders for total of "$459.00" mostly "Banana" product
When I view statistics for "WEB-POLAND" channel
When I view statistics
And I choose "WEB-POLAND" channel
Then I should see 4 new orders in the list
@no-api @ui
@no-api @ui @mink:chromedriver
Scenario: Seeing recent orders in a specific channel
Given 3 new customers have placed 4 orders for total of "$8,566.00" mostly "Onion" product
And 2 more new customers have placed 2 orders for total of "$459.00" mostly "Banana" product
When I view statistics for "WEB-US" channel
When I view statistics
And I choose "WEB-US" channel
Then I should see 2 new orders in the list

View file

@ -94,7 +94,9 @@ class DashboardPage extends SymfonyPage implements DashboardPageInterface
/** @throws ElementNotFoundException */
public function chooseChannel(string $channelName): void
{
$this->getElement('channel_choosing_link', ['%channelName%' => $channelName])->click();
$this->getElement('channel_choosing_button')->click();
$this->getElement('channel_choosing_list', ['%channelName%' => $channelName])->click();
$this->waitForAjaxUpdate();
}
/** @throws ElementNotFoundException */
@ -144,14 +146,15 @@ class DashboardPage extends SymfonyPage implements DashboardPageInterface
return array_merge(parent::getDefinedElements(), [
'admin_menu' => '.sylius-admin-menu',
'average_order_value' => '[data-test-average-order-value]',
'channel_choosing_link' => 'a:contains("%channelName%")',
'channel_choosing_button' => '[data-test-choose-channel-button]',
'channel_choosing_list' => '[data-test-choose-channel-list] a:contains("%channelName%")',
'customer_list' => '#customers',
'dropdown' => 'i.dropdown',
'logout' => '[data-test-user-dropdown-item="Logout"]',
'month_split_by_days_statistics_button' => 'button[data-stats-button="month"]',
'new_customers' => '[data-test-new-customers]',
'next_period' => '[data-test-next-period]',
'order_list' => '#orders',
'order_list' => '[data-test-new-orders]',
'paid_orders' => '[data-test-paid-orders]',
'previous_period' => '[data-test-previous-period]',
'product_navbar_search' => '[data-test-navbar-product-search]',

View file

@ -9,7 +9,7 @@
import ApexCharts from 'apexcharts';
var chart = null;
let chart = null;
function renderChart() {
// eslint-disable-next-line no-undef
const statisticsChart = document.querySelector('#statistics-chart');
@ -45,7 +45,8 @@ function renderChart() {
dataLabels: {
enabled: true,
formatter(val) {
return `${val}`;
const { currency } = statisticsChart.dataset;
return `${currency}${val}`;
},
offsetY: -20,
style: {
@ -88,7 +89,8 @@ function renderChart() {
labels: {
show: false,
formatter(val) {
return `${val}%`;
const { currency } = statisticsChart.dataset;
return `${currency}${val}`;
},
},
@ -109,10 +111,10 @@ function renderChart() {
renderChart();
let element = document.querySelector('#statistics-chart');
const element = document.querySelector('#statistics-chart');
if (element) {
let observer = new MutationObserver(function(mutations) {
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.attributeName === 'data-sales' || mutation.attributeName === 'data-intervals') {
chart.destroy();

View file

@ -21,10 +21,14 @@ twig_hooks:
template: '@SyliusAdmin/dashboard/index/content/latest_statistics.html.twig'
'sylius_admin.dashboard.index.content.header':
title_block:
template: '@SyliusAdmin/shared/crud/common/content/header/title_block.html.twig'
breadcrumbs:
template: '@SyliusAdmin/dashboard/index/content/header/breadcrumbs.html.twig'
title_block:
template: '@SyliusAdmin/dashboard/index/content/header/title_block/title.html.twig'
channel_selector:
component: 'sylius_admin:dashboard:channel_selector'
props:
channelCode: '@=_context.channel_code'
'sylius_admin.dashboard.index.content.header.title_block':
title:

View file

@ -107,6 +107,25 @@
/>
</service>
<service
id="sylius_admin.twig.component.dashboard.channel_selector"
class="Sylius\Bundle\AdminBundle\Twig\Component\Dashboard\ChannelSelectorComponent"
>
<argument type="service" id="sylius.repository.channel" />
<call method="setLiveResponder">
<argument type="service" id="ux.live_component.live_responder"/>
</call>
<tag
name="sylius.live_component"
key="sylius_admin:dashboard:channel_selector"
template="@SyliusAdmin/dashboard/index/component/channel_selector.html.twig"
/>
</service>
<service
id="sylius_admin.twig.component.dashboard.statistics"
class="Sylius\Bundle\AdminBundle\Twig\Component\Dashboard\StatisticsComponent"

View file

@ -0,0 +1,71 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Sylius\Bundle\AdminBundle\Twig\Component\Dashboard;
use Sylius\Component\Channel\Repository\ChannelRepositoryInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\TwigHooks\LiveComponent\HookableLiveComponentTrait;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveArg;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\ComponentToolsTrait;
use Symfony\UX\LiveComponent\DefaultActionTrait;
use Symfony\UX\TwigComponent\Attribute\ExposeInTemplate;
#[AsLiveComponent]
class ChannelSelectorComponent
{
use ComponentToolsTrait;
use DefaultActionTrait;
use HookableLiveComponentTrait;
#[LiveProp]
public string $channelCode = '';
/**
* @param ChannelRepositoryInterface<ChannelInterface> $channelRepository
*/
public function __construct(private readonly ChannelRepositoryInterface $channelRepository)
{
}
/**
* @return array<string, ChannelInterface>
*/
#[ExposeInTemplate(name: 'channels')]
public function getChannels(): array
{
return $this->channelRepository->findEnabled();
}
#[LiveAction]
public function changeChannel(
#[LiveArg] string $channelCode,
): void
{
$this->channelCode = $channelCode;
$this->emit('channelChanged', ['channelCode' => $channelCode]);
}
#[ExposeInTemplate(name: 'channelName')]
public function getChannelName(): string
{
$channel = $this->channelRepository->findOneByCode($this->channelCode);
return $channel ? $channel->getName() : '';
}
}

View file

@ -14,13 +14,16 @@ declare(strict_types=1);
namespace Sylius\Bundle\AdminBundle\Twig\Component\Dashboard;
use Sylius\Bundle\AdminBundle\Provider\StatisticsDataProviderInterface;
use Sylius\Bundle\MoneyBundle\Formatter\MoneyFormatterInterface;
use Sylius\Component\Channel\Repository\ChannelRepositoryInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Core\Statistics\Provider\StatisticsProviderInterface;
use Sylius\TwigHooks\LiveComponent\HookableLiveComponentTrait;
use Symfony\Component\Intl\Currencies;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveArg;
use Symfony\UX\LiveComponent\Attribute\LiveListener;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\ComponentToolsTrait;
use Symfony\UX\LiveComponent\DefaultActionTrait;
@ -75,10 +78,8 @@ class StatisticsComponent
$channel,
);
$result['business_activity_summary'] = $statistics->getBusinessActivitySummary();
$saleList = $statistics->getSales();
$result['sales_summary'] = [
$salesSummary = [
'intervals' => array_column($saleList, 'period'),
'sales' => array_map(
static function (int $total): string {
@ -88,7 +89,12 @@ class StatisticsComponent
),
];
return $result;
return [
'business_activity_summary' => $statistics->getBusinessActivitySummary(),
'channel' => $channel,
'currency_symbol' => Currencies::getSymbol($channel->getBaseCurrency()->getCode()),
'sales_summary' => $salesSummary,
];
}
#[LiveAction]
@ -103,6 +109,15 @@ class StatisticsComponent
$this->resolveDates();
}
#[LiveListener('channelChanged')]
public function changeChannel(
#[LiveArg] string $channelCode,
): void
{
$this->channelCode = $channelCode;
}
#[LiveAction]
public function getPreviousPeriod(): void
{

View file

@ -0,0 +1,23 @@
<div class="d-flex justify-content-end" {{ attributes }}>
<div class="dropdown">
<a class="btn btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false" {{ sylius_test_html_attribute('choose-channel-button') }}>
{{ channelName }}
</a>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuLink" {{ sylius_test_html_attribute('choose-channel-list') }}>
{% for channel in channels %}
<li>
<a
class="dropdown-item"
data-action="live#action"
data-live-action-param="changeChannel"
data-live-channel-code-param="{{ channel.code }}"
>
{{ channel.name }}
</a>
</li>
{% endfor %}
</ul>
</div>
</div>

View file

@ -6,7 +6,7 @@
<h3 class="card-title">{{ 'sylius.ui.new_orders'|trans }}</h3>
</div>
<div class="table-responsive">
<table class="table table-vcenter card-table">
<table class="table table-vcenter card-table" {{ sylius_test_html_attribute('new-orders') }}>
<thead>
<tr>
<th>{{ 'sylius.ui.customer'|trans }}</th>

View file

@ -1,6 +1,6 @@
<div
{{ sylius_test_html_attribute('statistics-component')}}
class="container-xl card m-3" {{ attributes }}
class="container-xl" {{ attributes }}
>
{% hook 'statistics' with {
statistics_data: statistics,

View file

@ -61,6 +61,6 @@
</button>
</div>
</div>
<div id="statistics-chart" class="chart-lg" data-intervals="{{ statistics_data.sales_summary.intervals|json_encode }}" data-sales="{{ statistics_data.sales_summary.sales|json_encode }}"></div>
<div id="statistics-chart" class="chart-lg" data-intervals="{{ statistics_data.sales_summary.intervals|json_encode }}" data-sales="{{ statistics_data.sales_summary.sales|json_encode }}" data-currency="{{ statistics_data.currency_symbol }}"></div>
</div>
</div>

View file

@ -19,7 +19,7 @@
<div class="col">
<div class="subheader">{{ 'sylius.ui.average_order_value'|trans }}</div>
<div class="h2 mb-0 me-2" {{ sylius_test_html_attribute('average-order-value') }}>
{{ statistics_data.business_activity_summary.averageOrderValue|sylius_format_money(sylius.currencyCode, sylius.localeCode) }}
{{ statistics_data.business_activity_summary.averageOrderValue|sylius_format_money(statistics_data.channel.baseCurrency.code, statistics_data.channel.defaultLocale.code) }}
</div>
</div>
</div>

View file

@ -20,7 +20,7 @@
<div class="col">
<div class="subheader">{{ 'sylius.ui.sales'|trans }}</div>
<div class="h2 mb-0 me-2" {{ sylius_test_html_attribute('total-sales') }}>
{{ statistics_data.business_activity_summary.totalSales|sylius_format_money(sylius.currencyCode, sylius.localeCode) }}
{{ statistics_data.business_activity_summary.totalSales|sylius_format_money(statistics_data.channel.baseCurrency.code, statistics_data.channel.defaultLocale.code) }}
</div>
</div>
</div>