= () => {
+ const classes = useStyles()
+ const { filter, setFilter } = useContext(salesDashboardContext)
+
+ const dateFilterLabel = filter
+ ? `${filter.dateFrom.format('ll')} - ${filter.dateTo.format('ll')}`
+ : 'Date Filter'
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+const useStyles = makeStyles((theme: Theme) => ({
+ iconNew: {
+ marginRight: 5,
+ },
+}))
+
+export default MainActions
diff --git a/src/SalesModule2/Overview/index.tsx b/src/SalesModule2/Overview/index.tsx
new file mode 100644
index 0000000..1de667a
--- /dev/null
+++ b/src/SalesModule2/Overview/index.tsx
@@ -0,0 +1 @@
+export { default } from './Overview'
diff --git a/src/SalesModule2/Overview/overviewContext.ts b/src/SalesModule2/Overview/overviewContext.ts
new file mode 100644
index 0000000..ed9fb0b
--- /dev/null
+++ b/src/SalesModule2/Overview/overviewContext.ts
@@ -0,0 +1,32 @@
+import React from 'react'
+import moment, { Moment } from 'moment'
+
+export interface SalesDahsboardContextFilter {
+ dateFrom: Moment
+ dateTo: Moment
+}
+
+export interface SalesDahsboardContext {
+ filter?: SalesDahsboardContextFilter
+ setFilter?: any
+}
+
+// The default context, which is used when there is no provider
+// (might be used for components testing)
+export const salesDashboardContextDefault: SalesDahsboardContext = {
+ filter: {
+ dateFrom: moment()
+ .subtract(14, 'day')
+ .startOf('day'),
+ dateTo: moment().startOf('day'),
+ },
+}
+
+export const salesDashboardContext = React.createContext(
+ salesDashboardContextDefault,
+)
+
+export const SalesDashboardProvider = salesDashboardContext.Provider
+export const SalesDashboardConsumer = salesDashboardContext.Consumer
+
+export default salesDashboardContext
diff --git a/src/SalesModule2/Payments/Payments.tsx b/src/SalesModule2/Payments/Payments.tsx
new file mode 100644
index 0000000..de49f4f
--- /dev/null
+++ b/src/SalesModule2/Payments/Payments.tsx
@@ -0,0 +1,7 @@
+import React from 'react'
+
+const Patments = () => {
+ return
+}
+
+export default Patments
diff --git a/src/SalesModule2/Products/ProductsCategoriesEditor/.gitkeep b/src/SalesModule2/Products/ProductsCategoriesEditor/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/src/SalesModule2/Products/ProductsCategoriesList/.gitkeep b/src/SalesModule2/Products/ProductsCategoriesList/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/src/SalesModule2/Products/ProductsEditor/.gitkeep b/src/SalesModule2/Products/ProductsEditor/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/src/SalesModule2/Products/ProductsList/.gitkeep b/src/SalesModule2/Products/ProductsList/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/src/Sales/Sales.tsx b/src/SalesModule2/Sales.tsx
similarity index 100%
rename from src/Sales/Sales.tsx
rename to src/SalesModule2/Sales.tsx
diff --git a/src/SalesModule2/SalesDocs.md b/src/SalesModule2/SalesDocs.md
new file mode 100644
index 0000000..07654b8
--- /dev/null
+++ b/src/SalesModule2/SalesDocs.md
@@ -0,0 +1,17 @@
+# Sales module
+
+The sales module is a good if you're planning to sell some goods in your system.
+It allows you to
+
+- See the sales overview dashboard
+- See and manage the orders
+- See and manage the payments
+- See and manage the products and categories
+- See and manage the stock of products (for physical products)
+- See and manage your products locations (stores, warehouses, shops, trading points, branches, etc)
+
+Use cases
+
+- Single store
+- Stores network
+- Delivery service
diff --git a/src/SalesModule2/Stock/Stock.tsx b/src/SalesModule2/Stock/Stock.tsx
new file mode 100644
index 0000000..af38661
--- /dev/null
+++ b/src/SalesModule2/Stock/Stock.tsx
@@ -0,0 +1,7 @@
+import React from 'react'
+
+const Stock = () => {
+ return Products Stock
+}
+
+export default Stock
diff --git a/src/SalesModule2/Stores/Stores.tsx b/src/SalesModule2/Stores/Stores.tsx
new file mode 100644
index 0000000..43f08b2
--- /dev/null
+++ b/src/SalesModule2/Stores/Stores.tsx
@@ -0,0 +1,7 @@
+import React from 'react'
+
+const Warehouses = () => {
+ return Warehouses
+}
+
+export default Warehouses
diff --git a/src/SalesModule2/_api/_data/categoriesData.ts b/src/SalesModule2/_api/_data/categoriesData.ts
new file mode 100644
index 0000000..8a7d404
--- /dev/null
+++ b/src/SalesModule2/_api/_data/categoriesData.ts
@@ -0,0 +1,84 @@
+import _keyBy from 'lodash/keyBy'
+import Category from '../../_types/ProductCategory'
+
+/*
+ Electronics, Computers & Office
+ ELECTRONICS
+ TV & Video
+ Home Audio & Theater
+ Cell Phones & Accessories
+ Wearable Technology
+ COMPUTERS
+ Computers, Tablets, & PC Products
+ Monitors
+ Drives & Storage
+ Books & Audible
+ Sports & Outdoors
+*/
+
+const list: Category[] = [
+ {
+ id: 1,
+ name: 'Electronics, Computers & Office',
+ },
+ {
+ id: 2,
+ name: 'Electronics',
+ parentId: 1,
+ },
+ {
+ id: 3,
+ name: 'TV & Video',
+ parentId: 2,
+ },
+ {
+ id: 4,
+ name: 'Home Audio & Theater',
+ parentId: 2,
+ },
+ {
+ id: 5,
+ name: 'Cell Phones & Accessories',
+ parentId: 2,
+ },
+ {
+ id: 6,
+ name: 'Wearable Technology',
+ parentId: 2,
+ },
+ {
+ id: 7,
+ name: 'Computers',
+ parentId: 1,
+ },
+ {
+ id: 8,
+ name: 'Computers, Tablets, & PC Products',
+ parentId: 7,
+ },
+ {
+ id: 9,
+ name: 'Monitors',
+ parentId: 7,
+ },
+ {
+ id: 10,
+ name: 'Drives & Storage',
+ parentId: 7,
+ },
+ {
+ id: 11,
+ name: 'Books & Audible',
+ },
+ {
+ id: 11,
+ name: 'Sports & Outdoors',
+ },
+]
+
+const byId: { [key: number]: Category } = _keyBy(list, 'id')
+
+export default {
+ list,
+ byId,
+}
diff --git a/src/SalesModule2/_api/_data/customersData.ts b/src/SalesModule2/_api/_data/customersData.ts
new file mode 100644
index 0000000..b1c6ea4
--- /dev/null
+++ b/src/SalesModule2/_api/_data/customersData.ts
@@ -0,0 +1 @@
+export default {}
diff --git a/src/SalesModule2/_api/_data/locationsData.ts b/src/SalesModule2/_api/_data/locationsData.ts
new file mode 100644
index 0000000..b1c6ea4
--- /dev/null
+++ b/src/SalesModule2/_api/_data/locationsData.ts
@@ -0,0 +1 @@
+export default {}
diff --git a/src/SalesModule2/_api/_data/ordersData.ts b/src/SalesModule2/_api/_data/ordersData.ts
new file mode 100644
index 0000000..574dc28
--- /dev/null
+++ b/src/SalesModule2/_api/_data/ordersData.ts
@@ -0,0 +1,86 @@
+import uuidv4 from 'uuid/v4'
+import moment, { Moment } from 'moment'
+import _keyBy from 'lodash/keyBy'
+import _sortBy from 'lodash/sortBy'
+import _random from 'lodash/random'
+import _shuffle from 'lodash/shuffle'
+import Order, { OrderStatus } from '../../_types/Order'
+import productsData from './productsData'
+
+const orderStatuses: OrderStatus[] = [
+ 'received',
+ 'preparing',
+ 'shipped',
+ 'delivered',
+ 'rejected',
+ 'refunded',
+]
+
+// Generate orders data for lat 90 days (do it one per browser session)
+const list = generateRandomOrdersHistory(90)
+const byId: { [key: number]: Order } = _keyBy(list, 'id')
+
+export default {
+ orderStatuses,
+ list,
+ byId,
+}
+
+export function generateRandomOrdersHistory(numDays: number) {
+ let list: Order[] = []
+ const now = moment()
+
+ for (
+ let date = moment().subtract(numDays, 'days'), dayNumber = 1;
+ date.isSameOrBefore(now);
+ date.add(1, 'day'), dayNumber++
+ ) {
+ const dailyOrders = generateDailyRandomOrders(date)
+
+ list = list.concat(dailyOrders)
+ }
+
+ return list
+}
+
+export function generateDailyRandomOrders(date: Moment): Order[] {
+ // Ensure the orders are date sorted
+ return _sortBy(
+ new Array(_random(0, 10)).fill(undefined).map(num => generateRandomOrder(date)),
+ order => moment(order.createdAt).toDate(),
+ )
+}
+
+export function generateRandomOrder(date: Moment): Order {
+ const shuffledProducts = _shuffle(productsData.list)
+ const numProducts = _random(1, 3)
+ const orderProductItems = shuffledProducts.slice(0, numProducts)
+ const orderProducts = orderProductItems.map(product => ({
+ id: product.id,
+ price: product.price,
+ quantity: _random(1, 2),
+ }))
+ const orderSum = orderProducts.reduce((sum, { price = 0, quantity = 0 }) => {
+ return sum + price * quantity
+ }, 0)
+ const isSuccessfulOrder = _random(1, 10) > 2
+ const orderStatus = isSuccessfulOrder
+ ? orderStatuses[_random(0, 3)]
+ : orderStatuses[_random(4, 5)]
+ const orderDate = moment(date).set({
+ hour: _random(0, 23),
+ minute: _random(0, 59),
+ second: _random(0, 59),
+ })
+
+ const order = {
+ id: uuidv4(),
+ products: orderProducts,
+ sum: orderSum,
+ status: orderStatus,
+ createdAt: orderDate.format(),
+ updatedAt: orderDate.format(),
+ }
+
+ return order
+}
diff --git a/src/SalesModule2/_api/_data/paymentsData.ts b/src/SalesModule2/_api/_data/paymentsData.ts
new file mode 100644
index 0000000..b1c6ea4
--- /dev/null
+++ b/src/SalesModule2/_api/_data/paymentsData.ts
@@ -0,0 +1 @@
+export default {}
diff --git a/src/SalesModule2/_api/_data/productsData.ts b/src/SalesModule2/_api/_data/productsData.ts
new file mode 100644
index 0000000..31b664e
--- /dev/null
+++ b/src/SalesModule2/_api/_data/productsData.ts
@@ -0,0 +1,50 @@
+import _keyBy from 'lodash/keyBy'
+import Product from '../../_types/Product'
+
+const list: Product[] = [
+ {
+ id: 1,
+ name: 'Simple Mobile Prepaid - Apple iPhone 6s (32GB) - Space Gray',
+ price: 300,
+ },
+ {
+ id: 2,
+ name: 'iPhoneXS',
+ price: 399,
+ },
+ {
+ id: 3,
+ name: 'Apple iPhone 6, GSM Unlocked, 64GB - Space Gray (Renewed)',
+ price: 500,
+ },
+ {
+ id: 4,
+ name: 'All-New Fire 7 Tablet (7" display, 16 GB) - Black',
+ images: [
+ {
+ url: 'https://images-na.ssl-images-amazon.com/images/I/61N1v5re7SL._SL1000_.jpg',
+ },
+ ],
+ price: 99.99,
+ },
+ {
+ id: 5,
+ name:
+ 'Echo (2nd Generation) - Smart speaker with Alexa and Dolby processing - Sandstone Fabric',
+ images: [
+ {
+ url: 'https://images-na.ssl-images-amazon.com/images/I/610d8E4usyL._SL1000_.jpg',
+ },
+ ],
+ price: 49.99,
+ },
+]
+
+const byId: { [key: number]: Product } = _keyBy(list, 'id')
+
+const productsData = {
+ list,
+ byId,
+}
+
+export default productsData
diff --git a/src/SalesModule2/_api/_data/productsRelCategoriesData.ts b/src/SalesModule2/_api/_data/productsRelCategoriesData.ts
new file mode 100644
index 0000000..b1c6ea4
--- /dev/null
+++ b/src/SalesModule2/_api/_data/productsRelCategoriesData.ts
@@ -0,0 +1 @@
+export default {}
diff --git a/src/SalesModule2/_api/_data/stockActionsData.ts b/src/SalesModule2/_api/_data/stockActionsData.ts
new file mode 100644
index 0000000..b1c6ea4
--- /dev/null
+++ b/src/SalesModule2/_api/_data/stockActionsData.ts
@@ -0,0 +1 @@
+export default {}
diff --git a/src/SalesModule2/_api/_data/stocksData.ts b/src/SalesModule2/_api/_data/stocksData.ts
new file mode 100644
index 0000000..b1c6ea4
--- /dev/null
+++ b/src/SalesModule2/_api/_data/stocksData.ts
@@ -0,0 +1 @@
+export default {}
diff --git a/src/SalesModule2/_api/_mocks/index.ts b/src/SalesModule2/_api/_mocks/index.ts
new file mode 100644
index 0000000..4ef664c
--- /dev/null
+++ b/src/SalesModule2/_api/_mocks/index.ts
@@ -0,0 +1,11 @@
+import MockAdapter from 'axios-mock-adapter'
+
+import ordersMocks from './ordersMocks'
+
+const init = (mockAdapter: MockAdapter) => {
+ ordersMocks.init(mockAdapter)
+}
+
+export default {
+ init,
+}
diff --git a/src/SalesModule2/_api/_mocks/ordersMocks.ts b/src/SalesModule2/_api/_mocks/ordersMocks.ts
new file mode 100644
index 0000000..b51697c
--- /dev/null
+++ b/src/SalesModule2/_api/_mocks/ordersMocks.ts
@@ -0,0 +1,67 @@
+import uuidv4 from 'uuid/v4'
+import moment from 'moment'
+import MockAdapter from 'axios-mock-adapter'
+import ordersData from '../_data/ordersData'
+
+export default {
+ init(mock: MockAdapter) {
+ mock.onGet('/orders').reply((config: any) => {
+ console.log('request config:', config)
+
+ const matchingOrders = ordersData.list
+ const ordersRes = matchingOrders.slice(0, 49)
+
+ return [
+ 200,
+ {
+ orders: ordersRes,
+ count: matchingOrders.length,
+ },
+ ]
+ })
+
+ //
+ mock.onGet(/\/orders\/.*?/).reply((config: any) => {
+ console.log('request config:', config)
+
+ const urlPaths = config.url.split('/')
+ const orderId = urlPaths[urlPaths.length - 1]
+ const order = ordersData.byId[orderId]
+
+ if (order) {
+ return [200, { ...order }]
+ } else {
+ return [404, { message: 'User not found ' }]
+ }
+ })
+
+ mock.onPut(/\/orders\/.*?/).reply((config: any) => {
+ const urlPaths = config.url.split('/')
+ const orderId = urlPaths[urlPaths.length - 1]
+ const orderData = JSON.parse(config.data)
+ const order = ordersData.byId[orderId]
+
+ if (order) {
+ return [200, { ...order, ...orderData }]
+ } else {
+ return [403, { message: 'Update not permitted' }]
+ }
+ })
+
+ mock.onPost(/\/orders/).reply((config: any) => {
+ const orderData = JSON.parse(config.data)
+ const order = {
+ ...orderData,
+ id: uuidv4(),
+ createdAt: moment().format(),
+ updatedAt: moment().format(),
+ }
+
+ return [200, order]
+ })
+
+ mock.onDelete(/\/orders\/\d+/).reply((config: any) => {
+ return [200, { message: 'Order removed' }]
+ })
+ },
+}
diff --git a/src/SalesModule2/_api/customers.ts b/src/SalesModule2/_api/customers.ts
new file mode 100644
index 0000000..61c0987
--- /dev/null
+++ b/src/SalesModule2/_api/customers.ts
@@ -0,0 +1,3 @@
+const customersService = {}
+
+export default customersService
diff --git a/src/SalesModule2/_api/index.ts b/src/SalesModule2/_api/index.ts
new file mode 100644
index 0000000..3759697
--- /dev/null
+++ b/src/SalesModule2/_api/index.ts
@@ -0,0 +1,20 @@
+import { AxiosInstance } from 'axios'
+import { ApiInitOptions } from '_api'
+
+import mocks from './_mocks'
+import orders from './orders'
+import MockAdapter from 'axios-mock-adapter/types'
+
+export interface SalesApiInitOptions extends ApiInitOptions {
+ instance: AxiosInstance
+ mockAdapter?: MockAdapter
+}
+
+const init = (options: SalesApiInitOptions) => {
+ if (options.useSampleData && options.mockAdapter) {
+ mocks.init(options.mockAdapter)
+ }
+}
+
+export default { init, orders }
+export { init, orders }
diff --git a/src/SalesModule2/_api/orders.ts b/src/SalesModule2/_api/orders.ts
new file mode 100644
index 0000000..d4db084
--- /dev/null
+++ b/src/SalesModule2/_api/orders.ts
@@ -0,0 +1,46 @@
+import { AxiosResponse } from 'axios'
+import Order, { OrderSubmissionData, OrderId } from '../_types/Order'
+import apiClient from '_api/client'
+
+export interface OrdersService {
+ getOne(orderId: OrderId): Promise
+ getList(params?: any): Promise
+ create(order: OrderSubmissionData): Promise
+ update(orderId: OrderId, order: OrderSubmissionData): Promise
+ remove(orderId: OrderId): Promise
+}
+
+export interface OrdersListResponse {
+ orders: Order[]
+ count: number
+}
+
+const ordersService: OrdersService = {
+ getOne(orderId) {
+ return apiClient
+ .get(`/orders/${orderId}`)
+ .then((res: AxiosResponse) => res.data)
+ },
+ getList(params: any) {
+ return apiClient
+ .get(`/orders`, {
+ params,
+ })
+ .then((res: AxiosResponse) => res.data)
+ },
+ create(order: OrderSubmissionData) {
+ return apiClient.post(`/orders`, order).then((res: AxiosResponse) => res.data)
+ },
+ update(orderId, order) {
+ return apiClient
+ .put(`/orders/${orderId}`, order)
+ .then((res: AxiosResponse) => res.data)
+ },
+ remove(orderId) {
+ return apiClient
+ .delete(`/orders/${orderId}`)
+ .then((res: AxiosResponse) => res.data)
+ },
+}
+
+export default ordersService
diff --git a/src/SalesModule2/_api/products.ts b/src/SalesModule2/_api/products.ts
new file mode 100644
index 0000000..0cba532
--- /dev/null
+++ b/src/SalesModule2/_api/products.ts
@@ -0,0 +1,3 @@
+const productsService = {}
+
+export default productsService
diff --git a/src/SalesModule2/_api/productsCategories.ts b/src/SalesModule2/_api/productsCategories.ts
new file mode 100644
index 0000000..c760c5f
--- /dev/null
+++ b/src/SalesModule2/_api/productsCategories.ts
@@ -0,0 +1,3 @@
+const productsCategoriesService = {}
+
+export default productsCategoriesService
diff --git a/src/SalesModule2/_services/.gitkeep b/src/SalesModule2/_services/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/src/SalesModule2/_types/Customer.ts b/src/SalesModule2/_types/Customer.ts
new file mode 100644
index 0000000..6fc701f
--- /dev/null
+++ b/src/SalesModule2/_types/Customer.ts
@@ -0,0 +1,10 @@
+import { EntityId } from '_types/Entity'
+
+export type CustomerId = EntityId
+
+export default interface Customer {
+ id?: CustomerId
+ name?: string
+ email?: string
+ details?: object
+}
diff --git a/src/SalesModule2/_types/EntityOwned.ts b/src/SalesModule2/_types/EntityOwned.ts
new file mode 100644
index 0000000..9b97a24
--- /dev/null
+++ b/src/SalesModule2/_types/EntityOwned.ts
@@ -0,0 +1,12 @@
+import Entity, { EntityId } from '_types/Entity'
+import { UserId } from '_types/User'
+import { OrganizationId } from '_types/Organization'
+
+export type EntitiyOwnedId = EntityId
+
+// The entity may be owned by an organization or an individual user
+export default interface EntityOwned extends Entity {
+ id?: EntityId
+ ownerUserId?: UserId
+ owenrOrganizationId?: OrganizationId
+}
diff --git a/src/SalesModule2/_types/Location.ts b/src/SalesModule2/_types/Location.ts
new file mode 100644
index 0000000..9e0a203
--- /dev/null
+++ b/src/SalesModule2/_types/Location.ts
@@ -0,0 +1,12 @@
+import EntityOwned, { EntitiyOwnedId } from './EntityOwned'
+
+export type LocationId = EntitiyOwnedId
+
+export default interface Location extends EntityOwned {
+ id?: LocationId
+ location?: {
+ lat: number
+ lng: number
+ }
+ name: string
+}
diff --git a/src/SalesModule2/_types/Order.ts b/src/SalesModule2/_types/Order.ts
new file mode 100644
index 0000000..378250d
--- /dev/null
+++ b/src/SalesModule2/_types/Order.ts
@@ -0,0 +1,36 @@
+import EntityOwned, { EntitiyOwnedId } from './EntityOwned'
+
+import { PaymentId } from './Payment'
+import { ProductId } from './Product'
+
+export type OrderId = EntitiyOwnedId
+export type OrderStatus =
+ | 'received'
+ | 'preparing'
+ | 'shipped'
+ | 'delivered'
+ | 'rejected'
+ | 'refunded'
+
+export interface OrderProduct {
+ id?: ProductId
+ price?: number
+ quantity?: number
+}
+
+export interface OrderSubmissionData {
+ products?: any[]
+ customerNotes?: string
+}
+
+// Order can be owned by a single account or user
+export default interface Order extends EntityOwned {
+ id?: OrderId
+ name?: string
+ status: OrderStatus
+ customerNotes?: string
+ staffNotes?: string
+ paymentId?: PaymentId
+ products?: any[]
+ sum: number
+}
diff --git a/src/SalesModule2/_types/Payment.ts b/src/SalesModule2/_types/Payment.ts
new file mode 100644
index 0000000..30f2a85
--- /dev/null
+++ b/src/SalesModule2/_types/Payment.ts
@@ -0,0 +1,10 @@
+import { EntityId } from '_types/Entity'
+
+export type PaymentId = EntityId
+
+export default interface Payment {
+ id?: PaymentId
+ status?: string
+ transactionId?: string
+ transactionStatus?: string
+}
diff --git a/src/SalesModule2/_types/Product.ts b/src/SalesModule2/_types/Product.ts
new file mode 100644
index 0000000..eee16b1
--- /dev/null
+++ b/src/SalesModule2/_types/Product.ts
@@ -0,0 +1,25 @@
+import Entity, { EntityId } from '_types/Entity'
+import { UserId } from '_types/User'
+import { OrganizationId } from '_types/Organization'
+import ProductImage from './ProductImage'
+
+export type ProductId = EntityId
+
+export interface ProductVariation {
+ name?: string
+ price?: number
+ details?: object
+}
+
+export default interface Product extends Entity {
+ id?: ProductId
+ name: string
+ details?: object
+ description?: string
+ variations?: ProductVariation[]
+ price: number
+ priceDiscounted?: number
+ images?: ProductImage[]
+ ownerUserId?: UserId
+ ownerOrganizationId?: OrganizationId
+}
diff --git a/src/SalesModule2/_types/ProductAttachment.ts b/src/SalesModule2/_types/ProductAttachment.ts
new file mode 100644
index 0000000..775b04f
--- /dev/null
+++ b/src/SalesModule2/_types/ProductAttachment.ts
@@ -0,0 +1,7 @@
+import Entity, { EntityId } from '_types/Entity'
+
+export default interface ProductAttachment extends Entity {
+ id?: EntityId
+ name?: string
+ url?: string
+}
diff --git a/src/SalesModule2/_types/ProductCategory.ts b/src/SalesModule2/_types/ProductCategory.ts
new file mode 100644
index 0000000..8a3a307
--- /dev/null
+++ b/src/SalesModule2/_types/ProductCategory.ts
@@ -0,0 +1,11 @@
+import EntityOwned, { EntitiyOwnedId } from './EntityOwned'
+import ProductImage from './ProductImage'
+
+export type ProductCategoryId = EntitiyOwnedId
+
+export default interface Category extends EntityOwned {
+ name: string
+ description?: string
+ parentId?: EntitiyOwnedId
+ images?: ProductImage[]
+}
diff --git a/src/SalesModule2/_types/ProductImage.ts b/src/SalesModule2/_types/ProductImage.ts
new file mode 100644
index 0000000..5dbb54b
--- /dev/null
+++ b/src/SalesModule2/_types/ProductImage.ts
@@ -0,0 +1,7 @@
+import Entity, { EntityId } from '_types/Entity'
+
+export default interface ProductImage extends Entity {
+ id?: EntityId
+ name?: string
+ url?: string
+}
diff --git a/src/SalesModule2/_types/ProductToProductCategory.ts b/src/SalesModule2/_types/ProductToProductCategory.ts
new file mode 100644
index 0000000..62084b5
--- /dev/null
+++ b/src/SalesModule2/_types/ProductToProductCategory.ts
@@ -0,0 +1,7 @@
+import { ProductId } from './Product'
+import { ProductCategoryId } from './ProductCategory'
+
+export default interface ProductToProductCategory {
+ productId: ProductId
+ productCategoryId: ProductCategoryId
+}
diff --git a/src/SalesModule2/_types/Stock.ts b/src/SalesModule2/_types/Stock.ts
new file mode 100644
index 0000000..7101501
--- /dev/null
+++ b/src/SalesModule2/_types/Stock.ts
@@ -0,0 +1,8 @@
+import { ProductId } from './Product'
+import { LocationId } from './Location'
+
+export default interface Stock {
+ productId: ProductId
+ locationId?: LocationId
+ qunatity: number
+}
diff --git a/src/SalesModule2/_types/StockAction.ts b/src/SalesModule2/_types/StockAction.ts
new file mode 100644
index 0000000..bc7d9b6
--- /dev/null
+++ b/src/SalesModule2/_types/StockAction.ts
@@ -0,0 +1,9 @@
+import { ProductId } from './Product'
+import { LocationId } from './Location'
+
+export default interface StockAction {
+ productId: ProductId
+ locationId?: LocationId
+ qunatity: number
+ action: string
+}
diff --git a/src/SalesModule2/index.tsx b/src/SalesModule2/index.tsx
new file mode 100644
index 0000000..4a32d0b
--- /dev/null
+++ b/src/SalesModule2/index.tsx
@@ -0,0 +1,11 @@
+import api from './_api'
+import Sales from './Sales'
+
+export interface InitOptions {}
+
+const init = (options: InitOptions) => {}
+
+const layout = 'DashboardLayout'
+
+export { default } from './Sales'
+export { init, api, layout, Sales }
diff --git a/src/Services/ServicesDocs.md b/src/ServicesModule/ServicesDocs.md
similarity index 100%
rename from src/Services/ServicesDocs.md
rename to src/ServicesModule/ServicesDocs.md
diff --git a/src/_api/index.ts b/src/_api/index.ts
index fa9279a..de59668 100644
--- a/src/_api/index.ts
+++ b/src/_api/index.ts
@@ -4,7 +4,7 @@ import organizations from './organizations'
import users from './users'
// Submodules
-import apiSales from '../Sales/_api'
+import apiSales from '../SalesModule/_api'
export interface ApiInitOptions {
useSampleData?: boolean
diff --git a/src/_layouts/BlankLayout/index.tsx b/src/_layouts/BlankLayout/index.tsx
index e69de29..1348e74 100644
--- a/src/_layouts/BlankLayout/index.tsx
+++ b/src/_layouts/BlankLayout/index.tsx
@@ -0,0 +1 @@
+export { default } from './BlankLayout'
diff --git a/src/_layouts/index.tsx b/src/_layouts/index.tsx
new file mode 100644
index 0000000..32170f6
--- /dev/null
+++ b/src/_layouts/index.tsx
@@ -0,0 +1,15 @@
+import React from 'react'
+import BlankLayout from './BlankLayout'
+import DashboardLayout from './DashboardLayout'
+
+const Wrapper = DashboardLayout
+
+const withDashboardLayout = (WrappedComponent: React.ComponentType) => {
+ return () => (
+
+
+
+ )
+}
+
+export { withDashboardLayout }