mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-30 19:52:20 +01:00
(merge) branch 'product-store_integration'
This commit is contained in:
commit
9e4d6028c5
@ -9,7 +9,6 @@ interface FabStateLabelProps {
|
||||
* Render a label preceded by a bot
|
||||
*/
|
||||
export const FabStateLabel: React.FC<FabStateLabelProps> = ({ status, background, children }) => {
|
||||
console.log('status: ', status);
|
||||
return (
|
||||
<span className={`fab-state-label ${status !== undefined ? status : ''} ${background ? 'bg' : ''}`}>
|
||||
{children}
|
||||
|
@ -4,12 +4,15 @@ import { useTranslation } from 'react-i18next';
|
||||
import { react2angular } from 'react2angular';
|
||||
import { Loader } from '../base/loader';
|
||||
import { IApplication } from '../../models/application';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { FabButton } from '../base/fab-button';
|
||||
import { StoreListHeader } from './store-list-header';
|
||||
import { AccordionItem } from './accordion-item';
|
||||
import { OrderItem } from './order-item';
|
||||
import { MemberSelect } from '../user/member-select';
|
||||
import { User } from '../../models/user';
|
||||
import { FormInput } from '../form/form-input';
|
||||
import { TDateISODate } from '../../typings/date-iso';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
@ -35,9 +38,10 @@ type checklistOption = { value: number, label: string };
|
||||
// TODO: delete next eslint disable
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const Orders: React.FC<OrdersProps> = ({ currentUser, onSuccess, onError }) => {
|
||||
console.log('currentUser: ', currentUser);
|
||||
const { t } = useTranslation('admin');
|
||||
|
||||
const { register, getValues } = useForm();
|
||||
|
||||
const [filters, setFilters] = useImmer<Filters>(initFilters);
|
||||
const [clearFilters, setClearFilters] = useState<boolean>(false);
|
||||
const [accordion, setAccordion] = useState({});
|
||||
@ -119,6 +123,13 @@ const Orders: React.FC<OrdersProps> = ({ currentUser, onSuccess, onError }) => {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter: by period
|
||||
*/
|
||||
const handlePeriod = () => {
|
||||
console.log(getValues(['period_from', 'period_to']));
|
||||
};
|
||||
|
||||
/**
|
||||
* Open/close accordion items
|
||||
*/
|
||||
@ -186,6 +197,27 @@ const Orders: React.FC<OrdersProps> = ({ currentUser, onSuccess, onError }) => {
|
||||
</div>
|
||||
</div>
|
||||
</AccordionItem>
|
||||
<AccordionItem id={3}
|
||||
isOpen={accordion[3]}
|
||||
onChange={handleAccordion}
|
||||
label={t('app.admin.store.orders.filter_period')}
|
||||
>
|
||||
<div className='content'>
|
||||
<div className="group">
|
||||
<div className="period">
|
||||
from
|
||||
<FormInput id="period_from"
|
||||
register={register}
|
||||
type="date" />
|
||||
to
|
||||
<FormInput id="period_to"
|
||||
register={register}
|
||||
type="date" />
|
||||
</div>
|
||||
<FabButton onClick={handlePeriod} className="is-info">{t('app.admin.store.orders.filter_apply')}</FabButton>
|
||||
</div>
|
||||
</div>
|
||||
</AccordionItem>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -216,11 +248,15 @@ Application.Components.component('orders', react2angular(OrdersWrapper, ['curren
|
||||
interface Filters {
|
||||
reference: string,
|
||||
status: checklistOption[],
|
||||
memberId: number
|
||||
memberId: number,
|
||||
period_from: TDateISODate,
|
||||
period_to: TDateISODate
|
||||
}
|
||||
|
||||
const initFilters: Filters = {
|
||||
reference: '',
|
||||
status: [],
|
||||
memberId: null
|
||||
memberId: null,
|
||||
period_from: null,
|
||||
period_to: null
|
||||
};
|
||||
|
@ -1,26 +1,76 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { IApplication } from '../../models/application';
|
||||
import { User } from '../../models/user';
|
||||
import { react2angular } from 'react2angular';
|
||||
import { Loader } from '../base/loader';
|
||||
import noImage from '../../../../images/no_image.png';
|
||||
import { FabStateLabel } from '../base/fab-state-label';
|
||||
import Select from 'react-select';
|
||||
|
||||
declare const Application: IApplication;
|
||||
|
||||
interface ShowOrderProps {
|
||||
orderRef: string,
|
||||
currentUser?: User,
|
||||
onError: (message: string) => void,
|
||||
onSuccess: (message: string) => void
|
||||
}
|
||||
/**
|
||||
* Option format, expected by react-select
|
||||
* @see https://github.com/JedWatson/react-select
|
||||
*/
|
||||
type selectOption = { value: number, label: string };
|
||||
|
||||
/**
|
||||
* This component shows an order details
|
||||
*/
|
||||
// TODO: delete next eslint disable
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export const ShowOrder: React.FC<ShowOrderProps> = ({ orderRef, onError, onSuccess }) => {
|
||||
const { t } = useTranslation('admin');
|
||||
export const ShowOrder: React.FC<ShowOrderProps> = ({ orderRef, currentUser, onError, onSuccess }) => {
|
||||
const { t } = useTranslation('shared');
|
||||
|
||||
/**
|
||||
* Check if the current operator has administrative rights or is a normal member
|
||||
*/
|
||||
const isPrivileged = (): boolean => {
|
||||
return (currentUser?.role === 'admin' || currentUser?.role === 'manager');
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates sorting options to the react-select format
|
||||
*/
|
||||
const buildOptions = (): Array<selectOption> => {
|
||||
return [
|
||||
{ value: 0, label: t('app.shared.store.show_order.status.error') },
|
||||
{ value: 1, label: t('app.shared.store.show_order.status.canceled') },
|
||||
{ value: 2, label: t('app.shared.store.show_order.status.pending') },
|
||||
{ value: 3, label: t('app.shared.store.show_order.status.under_preparation') },
|
||||
{ value: 4, label: t('app.shared.store.show_order.status.paid') },
|
||||
{ value: 5, label: t('app.shared.store.show_order.status.ready') },
|
||||
{ value: 6, label: t('app.shared.store.show_order.status.collected') },
|
||||
{ value: 7, label: t('app.shared.store.show_order.status.refunded') }
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback after selecting an action
|
||||
*/
|
||||
const handleAction = (action: selectOption) => {
|
||||
console.log('Action:', action);
|
||||
};
|
||||
|
||||
// Styles the React-select component
|
||||
const customStyles = {
|
||||
control: base => ({
|
||||
...base,
|
||||
width: '20ch',
|
||||
backgroundColor: 'transparent'
|
||||
}),
|
||||
indicatorSeparator: () => ({
|
||||
display: 'none'
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a className according to the status
|
||||
@ -43,28 +93,37 @@ export const ShowOrder: React.FC<ShowOrderProps> = ({ orderRef, onError, onSucce
|
||||
<header>
|
||||
<h2>[order.ref]</h2>
|
||||
<div className="grpBtn">
|
||||
{isPrivileged() &&
|
||||
<Select
|
||||
options={buildOptions()}
|
||||
onChange={option => handleAction(option)}
|
||||
styles={customStyles}
|
||||
/>
|
||||
}
|
||||
<a href={''}
|
||||
target='_blank'
|
||||
className='fab-button is-black'
|
||||
rel='noreferrer'>
|
||||
{t('app.admin.store.show_order.see_invoice')}
|
||||
{t('app.shared.store.show_order.see_invoice')}
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="client-info">
|
||||
<label>{t('app.admin.store.show_order.client')}</label>
|
||||
<label>{t('app.shared.store.show_order.tracking')}</label>
|
||||
<div className="content">
|
||||
{isPrivileged() &&
|
||||
<div className='group'>
|
||||
<span>{t('app.shared.store.show_order.client')}</span>
|
||||
<p>order.user.name</p>
|
||||
</div>
|
||||
}
|
||||
<div className='group'>
|
||||
<span>{t('app.admin.store.show_order.client')}</span>
|
||||
<p>order.user.name</p>
|
||||
</div>
|
||||
<div className='group'>
|
||||
<span>{t('app.admin.store.show_order.created_at')}</span>
|
||||
<span>{t('app.shared.store.show_order.created_at')}</span>
|
||||
<p>order.created_at</p>
|
||||
</div>
|
||||
<div className='group'>
|
||||
<span>{t('app.admin.store.show_order.last_update')}</span>
|
||||
<span>{t('app.shared.store.show_order.last_update')}</span>
|
||||
<p>order.???</p>
|
||||
</div>
|
||||
<FabStateLabel status={statusColor('error')} background>
|
||||
@ -74,7 +133,7 @@ export const ShowOrder: React.FC<ShowOrderProps> = ({ orderRef, onError, onSucce
|
||||
</div>
|
||||
|
||||
<div className="cart">
|
||||
<label>{t('app.admin.store.show_order.cart')}</label>
|
||||
<label>{t('app.shared.store.show_order.cart')}</label>
|
||||
<div>
|
||||
{/* loop sur les articles du panier */}
|
||||
<article className='store-cart-list-item'>
|
||||
@ -82,19 +141,19 @@ export const ShowOrder: React.FC<ShowOrderProps> = ({ orderRef, onError, onSucce
|
||||
<img alt=''src={noImage} />
|
||||
</div>
|
||||
<div className="ref">
|
||||
<span>{t('app.admin.store.show_order.reference_short')} orderable_id?</span>
|
||||
<span>{t('app.shared.store.show_order.reference_short')} orderable_id?</span>
|
||||
<p>o.orderable_name</p>
|
||||
</div>
|
||||
<div className="actions">
|
||||
<div className='price'>
|
||||
<p>o.amount</p>
|
||||
<span>/ {t('app.admin.store.show_order.unit')}</span>
|
||||
<span>/ {t('app.shared.store.show_order.unit')}</span>
|
||||
</div>
|
||||
|
||||
<span className="count">o.quantity</span>
|
||||
|
||||
<div className='total'>
|
||||
<span>{t('app.admin.store.show_order.item_total')}</span>
|
||||
<span>{t('app.shared.store.show_order.item_total')}</span>
|
||||
<p>o.quantity * o.amount</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -104,15 +163,15 @@ export const ShowOrder: React.FC<ShowOrderProps> = ({ orderRef, onError, onSucce
|
||||
|
||||
<div className="subgrid">
|
||||
<div className="payment-info">
|
||||
<label>{t('app.admin.store.show_order.payment_informations')}</label>
|
||||
<label>{t('app.shared.store.show_order.payment_informations')}</label>
|
||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ipsum rerum commodi quaerat possimus! Odit, harum.</p>
|
||||
</div>
|
||||
<div className="amount">
|
||||
<label>{t('app.admin.store.show_order.amount')}</label>
|
||||
<p>{t('app.admin.store.show_order.products_total')}<span>order.amount</span></p>
|
||||
<p className='gift'>{t('app.admin.store.show_order.gift_total')}<span>-order.amount</span></p>
|
||||
<p>{t('app.admin.store.show_order.coupon')}<span>order.amount</span></p>
|
||||
<p className='total'>{t('app.admin.store.show_order.total')} <span>order.total</span></p>
|
||||
<label>{t('app.shared.store.show_order.amount')}</label>
|
||||
<p>{t('app.shared.store.show_order.products_total')}<span>order.amount</span></p>
|
||||
<p className='gift'>{t('app.shared.store.show_order.gift_total')}<span>-order.amount</span></p>
|
||||
<p>{t('app.shared.store.show_order.coupon')}<span>order.amount</span></p>
|
||||
<p className='total'>{t('app.shared.store.show_order.cart_total')} <span>order.total</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -127,4 +186,4 @@ const ShowOrderWrapper: React.FC<ShowOrderProps> = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
Application.Components.component('showOrder', react2angular(ShowOrderWrapper, ['orderRef', 'onError', 'onSuccess']));
|
||||
Application.Components.component('showOrder', react2angular(ShowOrderWrapper, ['orderRef', 'currentUser', 'onError', 'onSuccess']));
|
||||
|
52
app/frontend/src/javascript/controllers/admin/orders.js
Normal file
52
app/frontend/src/javascript/controllers/admin/orders.js
Normal file
@ -0,0 +1,52 @@
|
||||
/* eslint-disable
|
||||
no-return-assign,
|
||||
no-undef,
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
Application.Controllers.controller('AdminShowOrdersController', ['$rootScope', '$scope', 'CSRF', 'growl', '$state', '$transition$',
|
||||
function ($rootScope, $scope, CSRF, growl, $state, $transition$) {
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
/* PUBLIC SCOPE */
|
||||
$scope.orderToken = $transition$.params().token;
|
||||
|
||||
/**
|
||||
* Callback triggered in case of error
|
||||
*/
|
||||
$scope.onError = (message) => {
|
||||
growl.error(message);
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback triggered in case of success
|
||||
*/
|
||||
$scope.onSuccess = (message) => {
|
||||
growl.success(message);
|
||||
};
|
||||
|
||||
/**
|
||||
* Click Callback triggered in case of back products list
|
||||
*/
|
||||
$scope.backProductsList = () => {
|
||||
$state.go('app.admin.store.orders');
|
||||
};
|
||||
|
||||
// currently logged-in user
|
||||
$scope.currentUser = $rootScope.currentUser;
|
||||
|
||||
/* PRIVATE SCOPE */
|
||||
|
||||
/**
|
||||
* Kind of constructor: these actions will be realized first when the controller is loaded
|
||||
*/
|
||||
const initialize = function () {
|
||||
// set the authenticity tokens in the forms
|
||||
CSRF.setMetaTags();
|
||||
};
|
||||
|
||||
// init the controller (call at the end !)
|
||||
return initialize();
|
||||
}
|
||||
|
||||
]);
|
@ -29,7 +29,7 @@ Application.Controllers.controller('ShowOrdersController', ['$rootScope', '$scop
|
||||
* Click Callback triggered in case of back products list
|
||||
*/
|
||||
$scope.backProductsList = () => {
|
||||
$state.go('app.admin.store.orders');
|
||||
$state.go('app.logged.dashboard.orders');
|
||||
};
|
||||
|
||||
// currently logged-in user
|
||||
|
@ -930,7 +930,7 @@ angular.module('application.router', ['ui.router'])
|
||||
views: {
|
||||
'main@': {
|
||||
templateUrl: '/admin/orders/show.html',
|
||||
controller: 'ShowOrdersController'
|
||||
controller: 'AdminShowOrdersController'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -35,6 +35,7 @@
|
||||
}
|
||||
.date { @include text-sm; }
|
||||
.price {
|
||||
flex: 0 1 30%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-self: flex-end;
|
||||
|
@ -143,4 +143,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.period {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
@ -12,8 +12,8 @@
|
||||
<div class="show-order-nav">
|
||||
<a class="back-btn" ng-click="backProductsList()" tabindex="0">
|
||||
<i class="fas fa-angle-left"></i>
|
||||
<span translate>{{ 'app.admin.store.back_products_list' }}</span>
|
||||
<span translate>{{ 'app.admin.store.back_to_list' }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<show-order order-token="orderToken" on-error="onError" on-success="onSuccess" />
|
||||
<show-order current-user="currentUser" order-ref="orderRef" on-error="onError" on-success="onSuccess" />
|
||||
</section>
|
@ -12,7 +12,7 @@
|
||||
<div class="edit-product-nav">
|
||||
<a class="back-btn" ng-click="backProductsList()">
|
||||
<i class="fas fa-angle-left"></i>
|
||||
<span translate>{{ 'app.admin.store.back_products_list' }}</span>
|
||||
<span translate>{{ 'app.admin.store.back_to_list' }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<edit-product product-id="productId" on-success="onSuccess" on-error="onError"/>
|
||||
|
@ -12,7 +12,7 @@
|
||||
<div class="new-product-nav">
|
||||
<a class="back-btn" ng-click="backProductsList()" tabindex="0">
|
||||
<i class="fas fa-angle-left"></i>
|
||||
<span translate>{{ 'app.admin.store.back_products_list' }}</span>
|
||||
<span translate>{{ 'app.admin.store.back_to_list' }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<new-product on-success="onSuccess" on-error="onError"/>
|
||||
|
17
app/frontend/templates/orders/show.html
Normal file
17
app/frontend/templates/orders/show.html
Normal file
@ -0,0 +1,17 @@
|
||||
<div>
|
||||
<section class="heading">
|
||||
<div class="row no-gutter">
|
||||
<ng-include src="'/dashboard/nav.html'"></ng-include>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="show-order-nav">
|
||||
<a class="back-btn" ng-click="backProductsList()" tabindex="0">
|
||||
<i class="fas fa-angle-left"></i>
|
||||
<span translate>{{ 'app.shared.store.show_order.back_to_list' }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<show-order current-user="currentUser" order-token="orderToken" on-error="onError" on-success="onSuccess" />
|
||||
</section>
|
||||
</div>
|
@ -1899,7 +1899,7 @@ en:
|
||||
all_products: "All products"
|
||||
categories_of_store: "Store's categories"
|
||||
the_orders: "Orders"
|
||||
back_products_list: "Back to products list"
|
||||
back_to_list: "Back to list"
|
||||
product_categories:
|
||||
title: "Categories"
|
||||
info: "<strong>Information:</strong></br>Find below all the categories created. The categories are arranged on two levels maximum, you can arrange them with a drag and drop. The order of the categories will be identical on the public view and the list below. Please note that you can delete a category or a sub-category even if they are associated with products. The latter will be left without categories. If you delete a category that contains sub-categories, the latter will also be deleted. <strong>Make sure that your categories are well arranged and save your choice.</strong>"
|
||||
@ -2037,6 +2037,7 @@ en:
|
||||
filter_ref: "By reference"
|
||||
filter_status: "By status"
|
||||
filter_client: "By client"
|
||||
filter_period: "By period"
|
||||
status:
|
||||
error: "Payment error"
|
||||
canceled: "Canceled"
|
||||
@ -2049,21 +2050,6 @@ en:
|
||||
sort:
|
||||
newest: "Newest first"
|
||||
oldest: "Oldest first"
|
||||
show_order:
|
||||
see_invoice: "See invoice"
|
||||
client: "Client"
|
||||
created_at: "Creation date"
|
||||
last_update: "Last update"
|
||||
cart: "Cart"
|
||||
reference_short: "ref:"
|
||||
unit: "Unit"
|
||||
item_total: "Total"
|
||||
payment_informations : "Payment informations"
|
||||
amount: "Amount"
|
||||
products_total: "Products total"
|
||||
gift_total: "Discount total"
|
||||
coupon: "Coupon"
|
||||
cart_total: "Cart total"
|
||||
store_settings:
|
||||
title: 'Settings'
|
||||
withdrawal_instructions: 'Product withdrawal instructions'
|
||||
|
@ -564,3 +564,29 @@ en:
|
||||
order_item:
|
||||
total: "Total"
|
||||
client: "Client"
|
||||
show_order:
|
||||
back_to_list: "Back to list"
|
||||
see_invoice: "See invoice"
|
||||
tracking: "Order tracking"
|
||||
client: "Client"
|
||||
created_at: "Creation date"
|
||||
last_update: "Last update"
|
||||
cart: "Cart"
|
||||
reference_short: "ref:"
|
||||
unit: "Unit"
|
||||
item_total: "Total"
|
||||
payment_informations : "Payment informations"
|
||||
amount: "Amount"
|
||||
products_total: "Products total"
|
||||
gift_total: "Discount total"
|
||||
coupon: "Coupon"
|
||||
cart_total: "Cart total"
|
||||
status:
|
||||
error: "Payment error"
|
||||
canceled: "Canceled"
|
||||
pending: "Pending payment"
|
||||
under_preparation: "Under preparation"
|
||||
paid: "Paid"
|
||||
ready: "Ready"
|
||||
collected: "Collected"
|
||||
refunded: "Refunded"
|
||||
|
Loading…
x
Reference in New Issue
Block a user