diff --git a/app/frontend/src/javascript/components/store/orders.tsx b/app/frontend/src/javascript/components/store/orders.tsx new file mode 100644 index 000000000..45c0dc3e8 --- /dev/null +++ b/app/frontend/src/javascript/components/store/orders.tsx @@ -0,0 +1,177 @@ +import React, { useState, useEffect } from 'react'; +import { useImmer } from 'use-immer'; +import { useTranslation } from 'react-i18next'; +import { react2angular } from 'react2angular'; +import { Loader } from '../base/loader'; +import { IApplication } from '../../models/application'; +import { FabButton } from '../base/fab-button'; +import { StoreListHeader } from './store-list-header'; +import { AccordionItem } from './accordion-item'; + +declare const Application: IApplication; + +interface OrdersProps { + onSuccess: (message: string) => void, + onError: (message: string) => void, +} +/** + * Option format, expected by react-select + * @see https://github.com/JedWatson/react-select + */ + type selectOption = { value: number, label: string }; + /** + * Option format, expected by checklist + */ +type checklistOption = { value: number, label: string }; +const statusOptions: checklistOption[] = [ + { value: 0, label: 'cart' }, + { value: 1, label: 'paid by credit card' }, + { value: 2, label: 'paid in cash' }, + { value: 3, label: 'being processed' }, + { value: 4, label: 'ready' }, + { value: 5, label: 'delivered' }, + { value: 6, label: 'canceled' }, + { value: 7, label: 'refunded' } +]; + +/** + * Admin list of orders + */ +const Orders: React.FC = ({ onSuccess, onError }) => { + const { t } = useTranslation('admin'); + + const [filters, setFilters] = useImmer(initFilters); + const [clearFilters, setClearFilters] = useState(false); + const [accordion, setAccordion] = useState({}); + + useEffect(() => { + applyFilters(); + setClearFilters(false); + }, [clearFilters]); + + /** + * Create a new order + */ + const newOrder = () => { + console.log('Create new order'); + }; + + /** + * Apply filters + */ + const applyFilters = () => { + console.log('Apply filters:', filters); + }; + + /** + * Clear filters + */ + const clearAllFilters = () => { + setFilters(initFilters); + setClearFilters(true); + console.log('Clear all filters'); + }; + + /** + * Creates sorting options to the react-select format + */ + const buildOptions = (): Array => { + return [ + { value: 0, label: t('app.admin.store.orders.sort.newest') }, + { value: 1, label: t('app.admin.store.orders.sort.oldest') } + ]; + }; + /** + * Display option: sorting + */ + const handleSorting = (option: selectOption) => { + console.log('Sort option:', option); + }; + + /** + * Filter: by status + */ + const handleSelectStatus = (s: checklistOption, checked) => { + const list = [...filters.status]; + checked + ? list.push(s) + : list.splice(list.indexOf(s), 1); + setFilters(draft => { + return { ...draft, status: list }; + }); + }; + + /** + * Open/close accordion items + */ + const handleAccordion = (id, state) => { + setAccordion({ ...accordion, [id]: state }); + }; + + return ( +
+
+

{t('app.admin.store.orders.heading')}

+
+ {t('app.admin.store.orders.create_order')} +
+
+ +
+
+

{t('app.admin.store.orders.filter')}

+
+ {t('app.admin.store.orders.filter_clear')} +
+
+
+ +
+
+ {statusOptions.map(s => ( + + ))} +
+ {t('app.admin.store.orders.filter_apply')} +
+
+
+
+ +
+ +
+
+ ); +}; + +const OrdersWrapper: React.FC = (props) => { + return ( + + + + ); +}; + +Application.Components.component('orders', react2angular(OrdersWrapper, ['onSuccess', 'onError'])); + +interface Filters { + reference: string, + status: checklistOption[] +} + +const initFilters: Filters = { + reference: '', + status: [] +}; diff --git a/app/frontend/src/javascript/components/store/products.tsx b/app/frontend/src/javascript/components/store/products.tsx index fab0408fe..19240f032 100644 --- a/app/frontend/src/javascript/components/store/products.tsx +++ b/app/frontend/src/javascript/components/store/products.tsx @@ -13,7 +13,7 @@ import ProductCategoryAPI from '../../api/product-category'; import MachineAPI from '../../api/machine'; import { AccordionItem } from './accordion-item'; import { X } from 'phosphor-react'; -import { ProductsListHeader } from './products-list-header'; +import { StoreListHeader } from './store-list-header'; declare const Application: IApplication; @@ -274,8 +274,8 @@ const Products: React.FC = ({ onSuccess, onError }) => { -
- + void, switchLabel?: string, - switchChecked: boolean, - onSwitch: (boolean) => void + switchChecked?: boolean, + onSwitch?: (boolean) => void } /** * Option format, expected by react-select @@ -20,7 +20,7 @@ interface ProductsListHeaderProps { /** * Renders an accordion item */ -export const ProductsListHeader: React.FC = ({ productsCount, selectOptions, onSelectOptionsChange, switchLabel, switchChecked, onSwitch }) => { +export const StoreListHeader: React.FC = ({ productsCount, selectOptions, onSelectOptionsChange, switchLabel, switchChecked, onSwitch }) => { const { t } = useTranslation('admin'); // Styles the React-select component @@ -37,32 +37,34 @@ export const ProductsListHeader: React.FC = ({ products }; return ( -
+
-

{t('app.admin.store.products_list_header.result_count')}{productsCount}

+

{t('app.admin.store.store_list_header.result_count')}{productsCount}

-

{t('app.admin.store.products_list_header.display_options')}

+

{t('app.admin.store.store_list_header.display_options')}