Compare commits
4 Commits
f50949a192
...
8adea62218
| Author | SHA1 | Date | |
|---|---|---|---|
| 8adea62218 | |||
| 349431c310 | |||
| 15ce7123a2 | |||
| 247bcc0ee5 |
2
Jenkinsfile
vendored
2
Jenkinsfile
vendored
@ -78,7 +78,7 @@ def buildOnLabel(label, buildCommand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stage("Archive Artifacts (${label})") {
|
stage("Archive Artifacts (${label})") {
|
||||||
archiveArtifacts artifacts: 'app_dist/**/*.dmg, app_dist/**/*.exe', fingerprint: true
|
archiveArtifacts artifacts: 'app_dist/**/*.dmg, app_dist/**/*.exe, app_dist/**/*.pkg', fingerprint: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
assets/dmg/background.png
Normal file
BIN
assets/dmg/background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
assets/dmg/background@2x.png
Normal file
BIN
assets/dmg/background@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
38
package.json
38
package.json
@ -148,11 +148,23 @@
|
|||||||
"arm64"
|
"arm64"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"target": "pkg",
|
||||||
|
"arch": [
|
||||||
|
"arm64"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"target": "dmg",
|
"target": "dmg",
|
||||||
"arch": [
|
"arch": [
|
||||||
"x64"
|
"x64"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"target": "pkg",
|
||||||
|
"arch": [
|
||||||
|
"x64"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"mergeASARs": true,
|
"mergeASARs": true,
|
||||||
@ -169,6 +181,32 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dmg": {
|
||||||
|
"background": "assets/dmg/background.png",
|
||||||
|
"iconSize": 100,
|
||||||
|
"window": {
|
||||||
|
"width": 540,
|
||||||
|
"height": 380
|
||||||
|
},
|
||||||
|
"contents": [
|
||||||
|
{
|
||||||
|
"x": 130,
|
||||||
|
"y": 220
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 410,
|
||||||
|
"y": 220,
|
||||||
|
"type": "link",
|
||||||
|
"path": "/Applications"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"pkg": {
|
||||||
|
"installLocation": "/Applications",
|
||||||
|
"mustClose": [
|
||||||
|
"com.tombutcher.farmcontrol"
|
||||||
|
]
|
||||||
|
},
|
||||||
"win": {
|
"win": {
|
||||||
"target": "nsis"
|
"target": "nsis"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -6,6 +6,7 @@ const __filename = fileURLToPath(import.meta.url)
|
|||||||
const __dirname = dirname(__filename)
|
const __dirname = dirname(__filename)
|
||||||
|
|
||||||
let win
|
let win
|
||||||
|
let sidebarViewMenuSections = []
|
||||||
|
|
||||||
const PROTOCOL_PREFIX = 'farmcontrol://'
|
const PROTOCOL_PREFIX = 'farmcontrol://'
|
||||||
|
|
||||||
@ -40,6 +41,76 @@ function sendNavigateToRenderer(redirectPath) {
|
|||||||
deliver()
|
deliver()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toElectronSidebarMenuItems(items = []) {
|
||||||
|
return items
|
||||||
|
.map((item) => {
|
||||||
|
if (item?.type === 'divider') {
|
||||||
|
return { type: 'separator' }
|
||||||
|
}
|
||||||
|
|
||||||
|
const menuItem = {
|
||||||
|
label: item.label
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item?.children && Array.isArray(item.children) && item.children.length) {
|
||||||
|
menuItem.submenu = toElectronSidebarMenuItems(item.children)
|
||||||
|
} else if (item?.path) {
|
||||||
|
menuItem.click = () => sendNavigateToRenderer(item.path)
|
||||||
|
} else {
|
||||||
|
menuItem.enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return menuItem
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildApplicationMenuTemplate() {
|
||||||
|
const env = (process.env.NODE_ENV || 'development').trim()
|
||||||
|
const viewSubmenu = sidebarViewMenuSections.map((section) => ({
|
||||||
|
label: section.label,
|
||||||
|
submenu: toElectronSidebarMenuItems(section.items || [])
|
||||||
|
}))
|
||||||
|
|
||||||
|
if (viewSubmenu.length === 0) {
|
||||||
|
viewSubmenu.push({ label: 'No sidebar items available', enabled: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env === 'development') {
|
||||||
|
viewSubmenu.push(
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
label: 'Toggle Developer Tools',
|
||||||
|
accelerator:
|
||||||
|
process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
|
||||||
|
click: () => {
|
||||||
|
if (win && !win.isDestroyed()) {
|
||||||
|
win.webContents.toggleDevTools()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const template = [
|
||||||
|
{ role: 'fileMenu' },
|
||||||
|
{ role: 'editMenu' },
|
||||||
|
{ label: 'View', submenu: viewSubmenu },
|
||||||
|
{ role: 'windowMenu' }
|
||||||
|
]
|
||||||
|
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
template.unshift({ role: 'appMenu' })
|
||||||
|
}
|
||||||
|
|
||||||
|
return template
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyApplicationMenu() {
|
||||||
|
const menu = Menu.buildFromTemplate(buildApplicationMenuTemplate())
|
||||||
|
Menu.setApplicationMenu(menu)
|
||||||
|
}
|
||||||
|
|
||||||
export function handleDeepLink(url) {
|
export function handleDeepLink(url) {
|
||||||
if (!url?.startsWith(`${PROTOCOL_PREFIX}app`)) return
|
if (!url?.startsWith(`${PROTOCOL_PREFIX}app`)) return
|
||||||
const redirectPath = url.replace(`${PROTOCOL_PREFIX}app`, '') || '/'
|
const redirectPath = url.replace(`${PROTOCOL_PREFIX}app`, '') || '/'
|
||||||
@ -118,29 +189,7 @@ export function createWindow() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Set up custom menu bar
|
applyApplicationMenu()
|
||||||
const env = (process.env.NODE_ENV || 'development').trim()
|
|
||||||
if (env === 'development') {
|
|
||||||
const devMenu = [
|
|
||||||
{
|
|
||||||
label: 'Developer',
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
label: 'Toggle Developer Tools',
|
|
||||||
accelerator:
|
|
||||||
process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
|
|
||||||
click: () => {
|
|
||||||
win.webContents.toggleDevTools()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
const menu = Menu.buildFromTemplate(devMenu)
|
|
||||||
Menu.setApplicationMenu(menu)
|
|
||||||
} else {
|
|
||||||
Menu.setApplicationMenu(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
// For development, load from localhost; for production, load the built index.html
|
// For development, load from localhost; for production, load the built index.html
|
||||||
if (process.env.ELECTRON_START_URL) {
|
if (process.env.ELECTRON_START_URL) {
|
||||||
@ -208,6 +257,16 @@ export function setupMainWindowIPC() {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('set-sidebar-view-menu', (event, sidebarSections) => {
|
||||||
|
if (!Array.isArray(sidebarSections)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
sidebarViewMenuSections = sidebarSections
|
||||||
|
applyApplicationMenu()
|
||||||
|
return true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setupMainWindowAppEvents(app) {
|
export function setupMainWindowAppEvents(app) {
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import { useContext, useEffect, useRef, useState } from 'react'
|
import { useContext, useEffect, useRef, useState } from 'react'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
import { Flex, Card, Alert } from 'antd'
|
import { Flex, Card, Alert, Button } from 'antd'
|
||||||
import { LoadingOutlined } from '@ant-design/icons'
|
import { LoadingOutlined } from '@ant-design/icons'
|
||||||
import { customAlphabet } from 'nanoid'
|
import { customAlphabet } from 'nanoid'
|
||||||
import AuthParticles from './AppParticles'
|
import AuthParticles from './AppParticles'
|
||||||
import FarmControlLogo from '../Logos/FarmControlLogo'
|
import FarmControlLogo from '../Logos/FarmControlLogo'
|
||||||
import ExclamationOctagonIcon from '../Icons/ExclamationOctagonIcon'
|
import ExclamationOctagonIcon from '../Icons/ExclamationOctagonIcon'
|
||||||
import CheckIcon from '../Icons/CheckIcon'
|
import CheckIcon from '../Icons/CheckIcon'
|
||||||
|
import ReloadIcon from '../Icons/ReloadIcon'
|
||||||
import { ApiServerContext } from '../Dashboard/context/ApiServerContext'
|
import { ApiServerContext } from '../Dashboard/context/ApiServerContext'
|
||||||
|
|
||||||
const createLaunchSession = customAlphabet(
|
const createLaunchSession = customAlphabet(
|
||||||
@ -24,6 +25,10 @@ const AuthLaunch = () => {
|
|||||||
const [launchErrorMessage, setLaunchErrorMessage] = useState('')
|
const [launchErrorMessage, setLaunchErrorMessage] = useState('')
|
||||||
const [launchSuccess, setLaunchSuccess] = useState(false)
|
const [launchSuccess, setLaunchSuccess] = useState(false)
|
||||||
|
|
||||||
|
const handleRefresh = () => {
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let cancelled = false
|
let cancelled = false
|
||||||
const redirect = new URLSearchParams(location.search).get('redirect')
|
const redirect = new URLSearchParams(location.search).get('redirect')
|
||||||
@ -168,12 +173,19 @@ const AuthLaunch = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{launchError && (
|
{launchError && (
|
||||||
<Alert
|
<>
|
||||||
message={launchErrorMessage}
|
<Alert
|
||||||
icon={<ExclamationOctagonIcon />}
|
message={launchErrorMessage}
|
||||||
type='error'
|
icon={<ExclamationOctagonIcon />}
|
||||||
showIcon
|
type='error'
|
||||||
/>
|
showIcon
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
icon={<ReloadIcon />}
|
||||||
|
onClick={handleRefresh}
|
||||||
|
size='large'
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
{launchSuccess && (
|
{launchSuccess && (
|
||||||
<Alert
|
<Alert
|
||||||
|
|||||||
@ -1,50 +1,14 @@
|
|||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
import DashboardSidebar from '../common/DashboardSidebar'
|
import DashboardSidebar from '../common/DashboardSidebar'
|
||||||
import { Typography } from 'antd'
|
import { getSidebarItems, getSidebarSelectedKey } from '../../../database/Sidebars'
|
||||||
|
|
||||||
const { Text } = Typography
|
|
||||||
|
|
||||||
const items = [
|
|
||||||
{
|
|
||||||
key: 'sessionstorage',
|
|
||||||
label: 'Session Storage',
|
|
||||||
icon: <Text>🗃️</Text>,
|
|
||||||
path: '/dashboard/developer/sessionstorage'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'authcontextdebug',
|
|
||||||
label: 'Auth Debug',
|
|
||||||
icon: <Text>🔐</Text>,
|
|
||||||
path: '/dashboard/developer/authcontextdebug'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'apicontextdebug',
|
|
||||||
label: 'API Debug',
|
|
||||||
icon: <Text>🌐</Text>,
|
|
||||||
path: '/dashboard/developer/apicontextdebug'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const routeKeyMap = {
|
|
||||||
'/dashboard/developer/sessionstorage': 'sessionstorage',
|
|
||||||
'/dashboard/developer/authcontextdebug': 'authcontextdebug',
|
|
||||||
'/dashboard/developer/apicontextdebug': 'apicontextdebug'
|
|
||||||
}
|
|
||||||
|
|
||||||
const DeveloperSidebar = (props) => {
|
const DeveloperSidebar = (props) => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const selectedKey = (() => {
|
const includeDev = import.meta.env.MODE === 'development'
|
||||||
const match = Object.keys(routeKeyMap).find((path) => {
|
const items = getSidebarItems('developer', { includeDev })
|
||||||
const pathSplit = path.split('/')
|
const selectedKey = getSidebarSelectedKey('developer', location.pathname, {
|
||||||
const locationPathSplit = location.pathname.split('/')
|
includeDev
|
||||||
if (pathSplit.length > locationPathSplit.length) return false
|
})
|
||||||
for (let i = 0; i < pathSplit.length; i++) {
|
|
||||||
if (pathSplit[i] !== locationPathSplit[i]) return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return match ? routeKeyMap[match] : 'sessionstorage'
|
|
||||||
})()
|
|
||||||
|
|
||||||
return <DashboardSidebar items={items} selectedKey={selectedKey} {...props} />
|
return <DashboardSidebar items={items} selectedKey={selectedKey} {...props} />
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,51 +1,14 @@
|
|||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
import DashboardSidebar from '../common/DashboardSidebar'
|
import DashboardSidebar from '../common/DashboardSidebar'
|
||||||
import InvoiceIcon from '../../Icons/InvoiceIcon'
|
import { getSidebarItems, getSidebarSelectedKey } from '../../../database/Sidebars'
|
||||||
import PaymentIcon from '../../Icons/PaymentIcon'
|
|
||||||
import FinanceIcon from '../../Icons/FinanceIcon'
|
|
||||||
|
|
||||||
const items = [
|
|
||||||
{
|
|
||||||
key: 'overview',
|
|
||||||
label: 'Overview',
|
|
||||||
icon: <FinanceIcon />,
|
|
||||||
path: '/dashboard/finance/overview'
|
|
||||||
},
|
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
key: 'invoices',
|
|
||||||
label: 'Invoices',
|
|
||||||
icon: <InvoiceIcon />,
|
|
||||||
path: '/dashboard/finance/invoices'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'payments',
|
|
||||||
label: 'Payments',
|
|
||||||
icon: <PaymentIcon />,
|
|
||||||
path: '/dashboard/finance/payments'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const routeKeyMap = {
|
|
||||||
'/dashboard/finance/overview': 'overview',
|
|
||||||
'/dashboard/finance/invoices': 'invoices',
|
|
||||||
'/dashboard/finance/payments': 'payments'
|
|
||||||
}
|
|
||||||
|
|
||||||
const FinanceSidebar = (props) => {
|
const FinanceSidebar = (props) => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const selectedKey = (() => {
|
const includeDev = import.meta.env.MODE === 'development'
|
||||||
const match = Object.keys(routeKeyMap).find((path) => {
|
const items = getSidebarItems('finance', { includeDev })
|
||||||
const pathSplit = path.split('/')
|
const selectedKey = getSidebarSelectedKey('finance', location.pathname, {
|
||||||
const locationPathSplit = location.pathname.split('/')
|
includeDev
|
||||||
if (pathSplit.length > locationPathSplit.length) return false
|
})
|
||||||
for (let i = 0; i < pathSplit.length; i++) {
|
|
||||||
if (pathSplit[i] !== locationPathSplit[i]) return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return match ? routeKeyMap[match] : 'overview'
|
|
||||||
})()
|
|
||||||
|
|
||||||
return <DashboardSidebar items={items} selectedKey={selectedKey} {...props} />
|
return <DashboardSidebar items={items} selectedKey={selectedKey} {...props} />
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,118 +1,14 @@
|
|||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
import DashboardSidebar from '../common/DashboardSidebar'
|
import DashboardSidebar from '../common/DashboardSidebar'
|
||||||
import FilamentStockIcon from '../../Icons/FilamentStockIcon'
|
import { getSidebarItems, getSidebarSelectedKey } from '../../../database/Sidebars'
|
||||||
import PartStockIcon from '../../Icons/PartStockIcon'
|
|
||||||
import ProductStockIcon from '../../Icons/ProductStockIcon'
|
|
||||||
import StockEventIcon from '../../Icons/StockEventIcon'
|
|
||||||
import StockAuditIcon from '../../Icons/StockAuditIcon'
|
|
||||||
import PurchaseOrderIcon from '../../Icons/PurchaseOrderIcon'
|
|
||||||
import ShipmentIcon from '../../Icons/ShipmentIcon'
|
|
||||||
import OrderItemIcon from '../../Icons/OrderItemIcon'
|
|
||||||
import InventoryIcon from '../../Icons/InventoryIcon'
|
|
||||||
import StockLocationIcon from '../../Icons/StockLocationIcon'
|
|
||||||
import StockTransferIcon from '../../Icons/StockTransferIcon'
|
|
||||||
|
|
||||||
const items = [
|
|
||||||
{
|
|
||||||
key: 'overview',
|
|
||||||
label: 'Overview',
|
|
||||||
icon: <InventoryIcon />,
|
|
||||||
path: '/dashboard/inventory/overview'
|
|
||||||
},
|
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
key: 'filamentstocks',
|
|
||||||
label: 'Filament Stocks',
|
|
||||||
icon: <FilamentStockIcon />,
|
|
||||||
path: '/dashboard/inventory/filamentstocks'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'partstocks',
|
|
||||||
label: 'Part Stocks',
|
|
||||||
icon: <PartStockIcon />,
|
|
||||||
path: '/dashboard/inventory/partstocks'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'productstocks',
|
|
||||||
label: 'Product Stocks',
|
|
||||||
icon: <ProductStockIcon />,
|
|
||||||
path: '/dashboard/inventory/productstocks'
|
|
||||||
},
|
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
key: 'purchaseorders',
|
|
||||||
label: 'Purchase Orders',
|
|
||||||
icon: <PurchaseOrderIcon />,
|
|
||||||
path: '/dashboard/inventory/purchaseorders'
|
|
||||||
},
|
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
key: 'orderitems',
|
|
||||||
label: 'Order Items',
|
|
||||||
icon: <OrderItemIcon />,
|
|
||||||
path: '/dashboard/inventory/orderitems'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'shipments',
|
|
||||||
label: 'Shipments',
|
|
||||||
icon: <ShipmentIcon />,
|
|
||||||
path: '/dashboard/inventory/shipments'
|
|
||||||
},
|
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
key: 'stocklocations',
|
|
||||||
label: 'Stock Locations',
|
|
||||||
icon: <StockLocationIcon />,
|
|
||||||
path: '/dashboard/inventory/stocklocations'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'stockevents',
|
|
||||||
label: 'Stock Events',
|
|
||||||
icon: <StockEventIcon />,
|
|
||||||
path: '/dashboard/inventory/stockevents'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'stockaudits',
|
|
||||||
label: 'Stock Audits',
|
|
||||||
icon: <StockAuditIcon />,
|
|
||||||
path: '/dashboard/inventory/stockaudits'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'stocktransfers',
|
|
||||||
label: 'Stock Transfers',
|
|
||||||
icon: <StockTransferIcon />,
|
|
||||||
path: '/dashboard/inventory/stocktransfers'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const routeKeyMap = {
|
|
||||||
'/dashboard/inventory/overview': 'overview',
|
|
||||||
'/dashboard/inventory/filamentstocks': 'filamentstocks',
|
|
||||||
'/dashboard/inventory/partstocks': 'partstocks',
|
|
||||||
'/dashboard/inventory/productstocks': 'productstocks',
|
|
||||||
'/dashboard/inventory/stocklocations': 'stocklocations',
|
|
||||||
'/dashboard/inventory/stocktransfers': 'stocktransfers',
|
|
||||||
'/dashboard/inventory/stockevents': 'stockevents',
|
|
||||||
'/dashboard/inventory/stockaudits': 'stockaudits',
|
|
||||||
'/dashboard/inventory/purchaseorders': 'purchaseorders',
|
|
||||||
'/dashboard/inventory/orderitems': 'orderitems',
|
|
||||||
'/dashboard/inventory/shipments': 'shipments'
|
|
||||||
}
|
|
||||||
|
|
||||||
const InventorySidebar = (props) => {
|
const InventorySidebar = (props) => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const selectedKey = (() => {
|
const includeDev = import.meta.env.MODE === 'development'
|
||||||
const match = Object.keys(routeKeyMap).find((path) => {
|
const items = getSidebarItems('inventory', { includeDev })
|
||||||
const pathSplit = path.split('/')
|
const selectedKey = getSidebarSelectedKey('inventory', location.pathname, {
|
||||||
const locationPathSplit = location.pathname.split('/')
|
includeDev
|
||||||
if (pathSplit.length > locationPathSplit.length) return false
|
})
|
||||||
for (let i = 0; i < pathSplit.length; i++) {
|
|
||||||
if (pathSplit[i] !== locationPathSplit[i]) return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return match ? routeKeyMap[match] : 'overview'
|
|
||||||
})()
|
|
||||||
|
|
||||||
return <DashboardSidebar items={items} selectedKey={selectedKey} {...props} />
|
return <DashboardSidebar items={items} selectedKey={selectedKey} {...props} />
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,244 +1,14 @@
|
|||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
import DashboardSidebar from '../common/DashboardSidebar'
|
import DashboardSidebar from '../common/DashboardSidebar'
|
||||||
import FilamentIcon from '../../Icons/FilamentIcon'
|
import { getSidebarItems, getSidebarSelectedKey } from '../../../database/Sidebars'
|
||||||
import FilamentSkuIcon from '../../Icons/FilamentSkuIcon'
|
|
||||||
import PartIcon from '../../Icons/PartIcon'
|
|
||||||
import PartSkuIcon from '../../Icons/PartSkuIcon'
|
|
||||||
import ProductIcon from '../../Icons/ProductIcon'
|
|
||||||
import ProductCategoryIcon from '../../Icons/ProductCategoryIcon'
|
|
||||||
import ProductSkuIcon from '../../Icons/ProductSkuIcon'
|
|
||||||
import VendorIcon from '../../Icons/VendorIcon'
|
|
||||||
import MaterialIcon from '../../Icons/MaterialIcon'
|
|
||||||
import NoteTypeIcon from '../../Icons/NoteTypeIcon'
|
|
||||||
import SettingsIcon from '../../Icons/SettingsIcon'
|
|
||||||
import AuditLogIcon from '../../Icons/AuditLogIcon'
|
|
||||||
import DeveloperIcon from '../../Icons/DeveloperIcon'
|
|
||||||
import PersonIcon from '../../Icons/PersonIcon'
|
|
||||||
import HostIcon from '../../Icons/HostIcon'
|
|
||||||
import DocumentPrinterIcon from '../../Icons/DocumentPrinterIcon'
|
|
||||||
import DocumentTemplateIcon from '../../Icons/DocumentTemplateIcon'
|
|
||||||
import DocumentIcon from '../../Icons/DocumentIcon'
|
|
||||||
import DocumentSizeIcon from '../../Icons/DocumentSizeIcon'
|
|
||||||
import DocumentJobIcon from '../../Icons/DocumentJobIcon'
|
|
||||||
import FileIcon from '../../Icons/FileIcon'
|
|
||||||
import CourierIcon from '../../Icons/CourierIcon'
|
|
||||||
import CourierServiceIcon from '../../Icons/CourierServiceIcon'
|
|
||||||
import TaxRateIcon from '../../Icons/TaxRateIcon'
|
|
||||||
import TaxRecordIcon from '../../Icons/TaxRecordIcon'
|
|
||||||
import AppPasswordIcon from '../../Icons/AppPasswordIcon'
|
|
||||||
|
|
||||||
const items = [
|
|
||||||
{
|
|
||||||
key: 'filaments',
|
|
||||||
icon: <FilamentIcon />,
|
|
||||||
label: 'Filaments',
|
|
||||||
path: '/dashboard/management/filaments'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'filamentSkus',
|
|
||||||
icon: <FilamentSkuIcon />,
|
|
||||||
label: 'Filament SKUs',
|
|
||||||
path: '/dashboard/management/filamentskus'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'parts',
|
|
||||||
icon: <PartIcon />,
|
|
||||||
label: 'Parts',
|
|
||||||
path: '/dashboard/management/parts'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'partSkus',
|
|
||||||
icon: <PartSkuIcon />,
|
|
||||||
label: 'Part SKUs',
|
|
||||||
path: '/dashboard/management/partskus'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'products',
|
|
||||||
icon: <ProductIcon />,
|
|
||||||
label: 'Products',
|
|
||||||
path: '/dashboard/management/products'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'productCategories',
|
|
||||||
icon: <ProductCategoryIcon />,
|
|
||||||
label: 'Product Categories',
|
|
||||||
path: '/dashboard/management/productcategories'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'productSkus',
|
|
||||||
icon: <ProductSkuIcon />,
|
|
||||||
label: 'Product SKUs',
|
|
||||||
path: '/dashboard/management/productskus'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'vendors',
|
|
||||||
icon: <VendorIcon />,
|
|
||||||
label: 'Vendors',
|
|
||||||
path: '/dashboard/management/vendors'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'materials',
|
|
||||||
icon: <MaterialIcon />,
|
|
||||||
label: 'Materials',
|
|
||||||
path: '/dashboard/management/materials'
|
|
||||||
},
|
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
key: 'couriers',
|
|
||||||
icon: <CourierIcon />,
|
|
||||||
label: 'Couriers',
|
|
||||||
path: '/dashboard/management/couriers'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'courierServices',
|
|
||||||
icon: <CourierServiceIcon />,
|
|
||||||
label: 'Courier Services',
|
|
||||||
path: '/dashboard/management/courierservices'
|
|
||||||
},
|
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
key: 'taxRates',
|
|
||||||
icon: <TaxRateIcon />,
|
|
||||||
label: 'Tax Rates',
|
|
||||||
path: '/dashboard/management/taxrates'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'taxRecords',
|
|
||||||
icon: <TaxRecordIcon />,
|
|
||||||
label: 'Tax Records',
|
|
||||||
path: '/dashboard/management/taxrecords'
|
|
||||||
},
|
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
key: 'noteTypes',
|
|
||||||
icon: <NoteTypeIcon />,
|
|
||||||
label: 'Note Types',
|
|
||||||
path: '/dashboard/management/notetypes'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'documents',
|
|
||||||
icon: <DocumentIcon />,
|
|
||||||
label: 'Documents',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
key: 'documentPrinters',
|
|
||||||
icon: <DocumentPrinterIcon />,
|
|
||||||
label: 'Document Printers',
|
|
||||||
path: '/dashboard/management/documentprinters'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'documentJobs',
|
|
||||||
icon: <DocumentJobIcon />,
|
|
||||||
label: 'Document Jobs',
|
|
||||||
path: '/dashboard/management/documentjobs'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'documentTemplates',
|
|
||||||
icon: <DocumentTemplateIcon />,
|
|
||||||
label: 'Document Templates',
|
|
||||||
path: '/dashboard/management/documenttemplates'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'documentSizes',
|
|
||||||
icon: <DocumentSizeIcon />,
|
|
||||||
label: 'Document Sizes',
|
|
||||||
path: '/dashboard/management/documentsizes'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
key: 'hosts',
|
|
||||||
icon: <HostIcon />,
|
|
||||||
label: 'Hosts',
|
|
||||||
path: '/dashboard/management/hosts'
|
|
||||||
},
|
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
key: 'users',
|
|
||||||
icon: <PersonIcon />,
|
|
||||||
label: 'Users',
|
|
||||||
path: '/dashboard/management/users'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'appPasswords',
|
|
||||||
icon: <AppPasswordIcon />,
|
|
||||||
label: 'App Passwords',
|
|
||||||
path: '/dashboard/management/apppasswords'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'settings',
|
|
||||||
icon: <SettingsIcon />,
|
|
||||||
label: 'Settings',
|
|
||||||
path: '/dashboard/management/settings'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'files',
|
|
||||||
icon: <FileIcon />,
|
|
||||||
label: 'Files',
|
|
||||||
path: '/dashboard/management/files'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'auditLogs',
|
|
||||||
icon: <AuditLogIcon />,
|
|
||||||
label: 'Audit Logs',
|
|
||||||
path: '/dashboard/management/auditlogs'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
if (import.meta.env.MODE === 'development') {
|
|
||||||
items.push(
|
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
key: 'developer',
|
|
||||||
icon: <DeveloperIcon />,
|
|
||||||
label: 'Developer',
|
|
||||||
path: '/dashboard/developer/sessionstorage'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const routeKeyMap = {
|
|
||||||
'/dashboard/management/filaments': 'filaments',
|
|
||||||
'/dashboard/management/filamentskus': 'filamentSkus',
|
|
||||||
'/dashboard/management/parts': 'parts',
|
|
||||||
'/dashboard/management/partskus': 'partSkus',
|
|
||||||
'/dashboard/management/users': 'users',
|
|
||||||
'/dashboard/management/apppasswords': 'appPasswords',
|
|
||||||
'/dashboard/management/products': 'products',
|
|
||||||
'/dashboard/management/productcategories': 'productCategories',
|
|
||||||
'/dashboard/management/productskus': 'productSkus',
|
|
||||||
'/dashboard/management/vendors': 'vendors',
|
|
||||||
'/dashboard/management/couriers': 'couriers',
|
|
||||||
'/dashboard/management/courierservices': 'courierServices',
|
|
||||||
'/dashboard/management/taxrates': 'taxRates',
|
|
||||||
'/dashboard/management/taxrecords': 'taxRecords',
|
|
||||||
'/dashboard/management/materials': 'materials',
|
|
||||||
'/dashboard/management/notetypes': 'noteTypes',
|
|
||||||
'/dashboard/management/settings': 'settings',
|
|
||||||
'/dashboard/management/auditlogs': 'auditLogs',
|
|
||||||
'/dashboard/management/files': 'files',
|
|
||||||
'/dashboard/management/hosts': 'hosts',
|
|
||||||
'/dashboard/management/documentsizes': 'documentSizes',
|
|
||||||
'/dashboard/management/documentprinters': 'documentPrinters',
|
|
||||||
'/dashboard/management/documenttemplates': 'documentTemplates',
|
|
||||||
'/dashboard/management/documentjobs': 'documentJobs'
|
|
||||||
}
|
|
||||||
|
|
||||||
const ManagementSidebar = (props) => {
|
const ManagementSidebar = (props) => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const selectedKey = (() => {
|
const includeDev = import.meta.env.MODE === 'development'
|
||||||
const match = Object.keys(routeKeyMap).find((path) => {
|
const items = getSidebarItems('management', { includeDev })
|
||||||
const pathSplit = path.split('/')
|
const selectedKey = getSidebarSelectedKey('management', location.pathname, {
|
||||||
const locationPathSplit = location.pathname.split('/')
|
includeDev
|
||||||
if (pathSplit.length > locationPathSplit.length) return false
|
})
|
||||||
for (let i = 0; i < pathSplit.length; i++) {
|
|
||||||
if (pathSplit[i] !== locationPathSplit[i]) return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return match ? routeKeyMap[match] : 'filaments'
|
|
||||||
})()
|
|
||||||
|
|
||||||
return <DashboardSidebar items={items} selectedKey={selectedKey} {...props} />
|
return <DashboardSidebar items={items} selectedKey={selectedKey} {...props} />
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,67 +1,14 @@
|
|||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
import DashboardSidebar from '../common/DashboardSidebar'
|
import DashboardSidebar from '../common/DashboardSidebar'
|
||||||
import ProductionIcon from '../../Icons/ProductionIcon'
|
import { getSidebarItems, getSidebarSelectedKey } from '../../../database/Sidebars'
|
||||||
import PrinterIcon from '../../Icons/PrinterIcon'
|
|
||||||
import JobIcon from '../../Icons/JobIcon'
|
|
||||||
import GCodeFileIcon from '../../Icons/GCodeFileIcon'
|
|
||||||
import SubJobIcon from '../../Icons/SubJobIcon'
|
|
||||||
|
|
||||||
const items = [
|
|
||||||
{
|
|
||||||
key: 'overview',
|
|
||||||
icon: <ProductionIcon />,
|
|
||||||
label: 'Overview',
|
|
||||||
path: '/dashboard/production/overview'
|
|
||||||
},
|
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
key: 'printers',
|
|
||||||
icon: <PrinterIcon />,
|
|
||||||
label: 'Printers',
|
|
||||||
path: '/dashboard/production/printers'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'jobs',
|
|
||||||
icon: <JobIcon />,
|
|
||||||
label: 'Jobs',
|
|
||||||
path: '/dashboard/production/jobs'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'subJobs',
|
|
||||||
icon: <SubJobIcon />,
|
|
||||||
label: 'Sub Jobs',
|
|
||||||
path: '/dashboard/production/subjobs'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'gcodeFiles',
|
|
||||||
icon: <GCodeFileIcon />,
|
|
||||||
label: 'GCode Files',
|
|
||||||
path: '/dashboard/production/gcodefiles'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const routeKeyMap = {
|
|
||||||
'/dashboard/production/overview': 'overview',
|
|
||||||
'/dashboard/production/printers': 'printers',
|
|
||||||
'/dashboard/production/jobs': 'jobs',
|
|
||||||
'/dashboard/production/subjobs': 'subJobs',
|
|
||||||
'/dashboard/production/gcodefiles': 'gcodeFiles'
|
|
||||||
}
|
|
||||||
|
|
||||||
const ProductionSidebar = (props) => {
|
const ProductionSidebar = (props) => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const selectedKey = (() => {
|
const includeDev = import.meta.env.MODE === 'development'
|
||||||
const match = Object.keys(routeKeyMap).find((path) => {
|
const items = getSidebarItems('production', { includeDev })
|
||||||
const pathSplit = path.split('/')
|
const selectedKey = getSidebarSelectedKey('production', location.pathname, {
|
||||||
const locationPathSplit = location.pathname.split('/')
|
includeDev
|
||||||
if (pathSplit.length > locationPathSplit.length) return false
|
})
|
||||||
for (let i = 0; i < pathSplit.length; i++) {
|
|
||||||
if (pathSplit[i] !== locationPathSplit[i]) return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return match ? routeKeyMap[match] : 'overview'
|
|
||||||
})()
|
|
||||||
|
|
||||||
return <DashboardSidebar items={items} selectedKey={selectedKey} {...props} />
|
return <DashboardSidebar items={items} selectedKey={selectedKey} {...props} />
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,68 +1,14 @@
|
|||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
import DashboardSidebar from '../common/DashboardSidebar'
|
import DashboardSidebar from '../common/DashboardSidebar'
|
||||||
import ClientIcon from '../../Icons/ClientIcon'
|
import { getSidebarItems, getSidebarSelectedKey } from '../../../database/Sidebars'
|
||||||
import SalesIcon from '../../Icons/SalesIcon'
|
|
||||||
import SalesOrderIcon from '../../Icons/SalesOrderIcon'
|
|
||||||
import MarketplaceIcon from '../../Icons/MarketplaceIcon'
|
|
||||||
import ListingIcon from '../../Icons/ListingIcon'
|
|
||||||
|
|
||||||
const items = [
|
|
||||||
{
|
|
||||||
key: 'overview',
|
|
||||||
label: 'Overview',
|
|
||||||
icon: <SalesIcon />,
|
|
||||||
path: '/dashboard/sales/overview'
|
|
||||||
},
|
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
key: 'clients',
|
|
||||||
label: 'Clients',
|
|
||||||
icon: <ClientIcon />,
|
|
||||||
path: '/dashboard/sales/clients'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'salesorders',
|
|
||||||
label: 'Sales Orders',
|
|
||||||
icon: <SalesOrderIcon />,
|
|
||||||
path: '/dashboard/sales/salesorders'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'marketplaces',
|
|
||||||
label: 'Marketplaces',
|
|
||||||
icon: <MarketplaceIcon />,
|
|
||||||
path: '/dashboard/sales/marketplaces'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'listings',
|
|
||||||
label: 'Listings',
|
|
||||||
icon: <ListingIcon />,
|
|
||||||
path: '/dashboard/sales/listings'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const routeKeyMap = {
|
|
||||||
'/dashboard/sales/overview': 'overview',
|
|
||||||
'/dashboard/sales/clients': 'clients',
|
|
||||||
'/dashboard/sales/salesorders': 'salesorders',
|
|
||||||
'/dashboard/sales/marketplaces': 'marketplaces',
|
|
||||||
'/dashboard/sales/listings': 'listings',
|
|
||||||
'/dashboard/sales/listingvarients': 'listings'
|
|
||||||
}
|
|
||||||
|
|
||||||
const SalesSidebar = (props) => {
|
const SalesSidebar = (props) => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const selectedKey = (() => {
|
const includeDev = import.meta.env.MODE === 'development'
|
||||||
const match = Object.keys(routeKeyMap).find((path) => {
|
const items = getSidebarItems('sales', { includeDev })
|
||||||
const pathSplit = path.split('/')
|
const selectedKey = getSidebarSelectedKey('sales', location.pathname, {
|
||||||
const locationPathSplit = location.pathname.split('/')
|
includeDev
|
||||||
if (pathSplit.length > locationPathSplit.length) return false
|
})
|
||||||
for (let i = 0; i < pathSplit.length; i++) {
|
|
||||||
if (pathSplit[i] !== locationPathSplit[i]) return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return match ? routeKeyMap[match] : 'overview'
|
|
||||||
})()
|
|
||||||
|
|
||||||
return <DashboardSidebar items={items} selectedKey={selectedKey} {...props} />
|
return <DashboardSidebar items={items} selectedKey={selectedKey} {...props} />
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,10 @@ import SettingsIcon from '../../Icons/SettingsIcon'
|
|||||||
import DeveloperIcon from '../../Icons/DeveloperIcon'
|
import DeveloperIcon from '../../Icons/DeveloperIcon'
|
||||||
import { ElectronContext } from '../context/ElectronContext'
|
import { ElectronContext } from '../context/ElectronContext'
|
||||||
import DashboardWindowButtons from './DashboardWindowButtons'
|
import DashboardWindowButtons from './DashboardWindowButtons'
|
||||||
|
import {
|
||||||
|
getSidebarDefaultPath,
|
||||||
|
getSidebarMenuSections
|
||||||
|
} from '../../../database/Sidebars'
|
||||||
|
|
||||||
const { Text } = Typography
|
const { Text } = Typography
|
||||||
|
|
||||||
@ -57,7 +61,8 @@ const DashboardNavigation = () => {
|
|||||||
icon: <ProductionIcon />
|
icon: <ProductionIcon />
|
||||||
})
|
})
|
||||||
const isMobile = useMediaQuery({ maxWidth: 768 })
|
const isMobile = useMediaQuery({ maxWidth: 768 })
|
||||||
const { platform, isElectron, isFullScreen } = useContext(ElectronContext)
|
const { platform, isElectron, isFullScreen, setSidebarViewMenu } =
|
||||||
|
useContext(ElectronContext)
|
||||||
|
|
||||||
const mainMenuItems = useMemo(
|
const mainMenuItems = useMemo(
|
||||||
() => [
|
() => [
|
||||||
@ -117,19 +122,16 @@ const DashboardNavigation = () => {
|
|||||||
}, [connecting, connected])
|
}, [connecting, connected])
|
||||||
|
|
||||||
const handleMainMenuClick = ({ key }) => {
|
const handleMainMenuClick = ({ key }) => {
|
||||||
if (key === 'production') {
|
navigate(getSidebarDefaultPath(key, { includeDev: import.meta.env.DEV }))
|
||||||
navigate('/dashboard/production/overview')
|
|
||||||
} else if (key === 'inventory') {
|
|
||||||
navigate('/dashboard/inventory/overview')
|
|
||||||
} else if (key === 'finance') {
|
|
||||||
navigate('/dashboard/finance/overview')
|
|
||||||
} else if (key === 'sales') {
|
|
||||||
navigate('/dashboard/sales/overview')
|
|
||||||
} else if (key === 'management') {
|
|
||||||
navigate('/dashboard/management/filaments')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isElectron || !setSidebarViewMenu) return
|
||||||
|
const includeDev = import.meta.env.DEV
|
||||||
|
const sections = getSidebarMenuSections({ includeDev })
|
||||||
|
setSidebarViewMenu(sections)
|
||||||
|
}, [isElectron, setSidebarViewMenu])
|
||||||
|
|
||||||
const showAppLogo =
|
const showAppLogo =
|
||||||
(isElectron && platform == 'darwin' && isFullScreen == true) ||
|
(isElectron && platform == 'darwin' && isFullScreen == true) ||
|
||||||
(isElectron && platform != 'darwin')
|
(isElectron && platform != 'darwin')
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { useMediaQuery } from 'react-responsive'
|
|||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { ElectronContext } from '../context/ElectronContext'
|
import { ElectronContext } from '../context/ElectronContext'
|
||||||
|
import { getSidebarIconNode } from '../../Icons/sidebarIconMap'
|
||||||
const { Sider } = Layout
|
const { Sider } = Layout
|
||||||
|
|
||||||
const DashboardSidebar = ({
|
const DashboardSidebar = ({
|
||||||
@ -47,7 +48,7 @@ const DashboardSidebar = ({
|
|||||||
|
|
||||||
const mappedItem = {
|
const mappedItem = {
|
||||||
key: item.key,
|
key: item.key,
|
||||||
icon: item.icon,
|
icon: item.icon || getSidebarIconNode(item.iconKey),
|
||||||
label: item.label
|
label: item.label
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { createContext, useEffect, useState } from 'react'
|
import { createContext, useCallback, useEffect, useState } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
@ -144,6 +144,14 @@ const ElectronProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setSidebarViewMenu = useCallback(
|
||||||
|
async (sections) => {
|
||||||
|
if (!electronAvailable || !ipcRenderer) return false
|
||||||
|
return await ipcRenderer.invoke('set-sidebar-view-menu', sections)
|
||||||
|
},
|
||||||
|
[electronAvailable]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ElectronContext.Provider
|
<ElectronContext.Provider
|
||||||
value={{
|
value={{
|
||||||
@ -159,7 +167,8 @@ const ElectronProvider = ({ children }) => {
|
|||||||
clearAuthSession,
|
clearAuthSession,
|
||||||
getToken,
|
getToken,
|
||||||
setToken,
|
setToken,
|
||||||
resizeSpotlightWindow
|
resizeSpotlightWindow,
|
||||||
|
setSidebarViewMenu
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
113
src/components/Icons/sidebarIconMap.jsx
Normal file
113
src/components/Icons/sidebarIconMap.jsx
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import ProductionIcon from './ProductionIcon'
|
||||||
|
import PrinterIcon from './PrinterIcon'
|
||||||
|
import JobIcon from './JobIcon'
|
||||||
|
import GCodeFileIcon from './GCodeFileIcon'
|
||||||
|
import SubJobIcon from './SubJobIcon'
|
||||||
|
import InventoryIcon from './InventoryIcon'
|
||||||
|
import FilamentStockIcon from './FilamentStockIcon'
|
||||||
|
import PartStockIcon from './PartStockIcon'
|
||||||
|
import ProductStockIcon from './ProductStockIcon'
|
||||||
|
import StockEventIcon from './StockEventIcon'
|
||||||
|
import StockAuditIcon from './StockAuditIcon'
|
||||||
|
import PurchaseOrderIcon from './PurchaseOrderIcon'
|
||||||
|
import ShipmentIcon from './ShipmentIcon'
|
||||||
|
import OrderItemIcon from './OrderItemIcon'
|
||||||
|
import StockLocationIcon from './StockLocationIcon'
|
||||||
|
import StockTransferIcon from './StockTransferIcon'
|
||||||
|
import SalesIcon from './SalesIcon'
|
||||||
|
import ClientIcon from './ClientIcon'
|
||||||
|
import SalesOrderIcon from './SalesOrderIcon'
|
||||||
|
import MarketplaceIcon from './MarketplaceIcon'
|
||||||
|
import ListingIcon from './ListingIcon'
|
||||||
|
import FinanceIcon from './FinanceIcon'
|
||||||
|
import InvoiceIcon from './InvoiceIcon'
|
||||||
|
import PaymentIcon from './PaymentIcon'
|
||||||
|
import FilamentIcon from './FilamentIcon'
|
||||||
|
import FilamentSkuIcon from './FilamentSkuIcon'
|
||||||
|
import PartIcon from './PartIcon'
|
||||||
|
import PartSkuIcon from './PartSkuIcon'
|
||||||
|
import ProductIcon from './ProductIcon'
|
||||||
|
import ProductCategoryIcon from './ProductCategoryIcon'
|
||||||
|
import ProductSkuIcon from './ProductSkuIcon'
|
||||||
|
import VendorIcon from './VendorIcon'
|
||||||
|
import MaterialIcon from './MaterialIcon'
|
||||||
|
import NoteTypeIcon from './NoteTypeIcon'
|
||||||
|
import SettingsIcon from './SettingsIcon'
|
||||||
|
import AuditLogIcon from './AuditLogIcon'
|
||||||
|
import DeveloperIcon from './DeveloperIcon'
|
||||||
|
import PersonIcon from './PersonIcon'
|
||||||
|
import HostIcon from './HostIcon'
|
||||||
|
import DocumentPrinterIcon from './DocumentPrinterIcon'
|
||||||
|
import DocumentTemplateIcon from './DocumentTemplateIcon'
|
||||||
|
import DocumentIcon from './DocumentIcon'
|
||||||
|
import DocumentSizeIcon from './DocumentSizeIcon'
|
||||||
|
import DocumentJobIcon from './DocumentJobIcon'
|
||||||
|
import FileIcon from './FileIcon'
|
||||||
|
import CourierIcon from './CourierIcon'
|
||||||
|
import CourierServiceIcon from './CourierServiceIcon'
|
||||||
|
import TaxRateIcon from './TaxRateIcon'
|
||||||
|
import TaxRecordIcon from './TaxRecordIcon'
|
||||||
|
import AppPasswordIcon from './AppPasswordIcon'
|
||||||
|
|
||||||
|
const toEmoji = (emoji) => <span aria-hidden>{emoji}</span>
|
||||||
|
|
||||||
|
const sidebarIconMap = {
|
||||||
|
production: <ProductionIcon />,
|
||||||
|
printer: <PrinterIcon />,
|
||||||
|
job: <JobIcon />,
|
||||||
|
subJob: <SubJobIcon />,
|
||||||
|
gcodeFile: <GCodeFileIcon />,
|
||||||
|
inventory: <InventoryIcon />,
|
||||||
|
filamentStock: <FilamentStockIcon />,
|
||||||
|
partStock: <PartStockIcon />,
|
||||||
|
productStock: <ProductStockIcon />,
|
||||||
|
stockEvent: <StockEventIcon />,
|
||||||
|
stockAudit: <StockAuditIcon />,
|
||||||
|
purchaseOrder: <PurchaseOrderIcon />,
|
||||||
|
orderItem: <OrderItemIcon />,
|
||||||
|
shipment: <ShipmentIcon />,
|
||||||
|
stockLocation: <StockLocationIcon />,
|
||||||
|
stockTransfer: <StockTransferIcon />,
|
||||||
|
sales: <SalesIcon />,
|
||||||
|
client: <ClientIcon />,
|
||||||
|
salesOrder: <SalesOrderIcon />,
|
||||||
|
marketplace: <MarketplaceIcon />,
|
||||||
|
listing: <ListingIcon />,
|
||||||
|
finance: <FinanceIcon />,
|
||||||
|
invoice: <InvoiceIcon />,
|
||||||
|
payment: <PaymentIcon />,
|
||||||
|
filament: <FilamentIcon />,
|
||||||
|
filamentSku: <FilamentSkuIcon />,
|
||||||
|
part: <PartIcon />,
|
||||||
|
partSku: <PartSkuIcon />,
|
||||||
|
product: <ProductIcon />,
|
||||||
|
productCategory: <ProductCategoryIcon />,
|
||||||
|
productSku: <ProductSkuIcon />,
|
||||||
|
vendor: <VendorIcon />,
|
||||||
|
material: <MaterialIcon />,
|
||||||
|
noteType: <NoteTypeIcon />,
|
||||||
|
settings: <SettingsIcon />,
|
||||||
|
auditLog: <AuditLogIcon />,
|
||||||
|
developer: <DeveloperIcon />,
|
||||||
|
person: <PersonIcon />,
|
||||||
|
host: <HostIcon />,
|
||||||
|
documentPrinter: <DocumentPrinterIcon />,
|
||||||
|
documentTemplate: <DocumentTemplateIcon />,
|
||||||
|
document: <DocumentIcon />,
|
||||||
|
documentSize: <DocumentSizeIcon />,
|
||||||
|
documentJob: <DocumentJobIcon />,
|
||||||
|
file: <FileIcon />,
|
||||||
|
courier: <CourierIcon />,
|
||||||
|
courierService: <CourierServiceIcon />,
|
||||||
|
taxRate: <TaxRateIcon />,
|
||||||
|
taxRecord: <TaxRecordIcon />,
|
||||||
|
appPassword: <AppPasswordIcon />,
|
||||||
|
sessionStorage: toEmoji('🗃️'),
|
||||||
|
authDebug: toEmoji('🔐'),
|
||||||
|
apiDebug: toEmoji('🌐')
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getSidebarIconNode = (iconKey) => {
|
||||||
|
if (!iconKey) return null
|
||||||
|
return sidebarIconMap[iconKey] || null
|
||||||
|
}
|
||||||
160
src/database/Sidebars.js
Normal file
160
src/database/Sidebars.js
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
import productionSidebarItems from './sidebars/production'
|
||||||
|
import inventorySidebarItems from './sidebars/inventory'
|
||||||
|
import salesSidebarItems from './sidebars/sales'
|
||||||
|
import financeSidebarItems from './sidebars/finance'
|
||||||
|
import managementSidebarItems from './sidebars/management'
|
||||||
|
import developerSidebarItems from './sidebars/developer'
|
||||||
|
|
||||||
|
const SIDEBARS = {
|
||||||
|
production: {
|
||||||
|
key: 'production',
|
||||||
|
label: 'Production',
|
||||||
|
iconKey: 'production',
|
||||||
|
items: productionSidebarItems
|
||||||
|
},
|
||||||
|
inventory: {
|
||||||
|
key: 'inventory',
|
||||||
|
label: 'Inventory',
|
||||||
|
iconKey: 'inventory',
|
||||||
|
items: inventorySidebarItems
|
||||||
|
},
|
||||||
|
sales: {
|
||||||
|
key: 'sales',
|
||||||
|
label: 'Sales',
|
||||||
|
iconKey: 'sales',
|
||||||
|
items: salesSidebarItems,
|
||||||
|
routeAliases: {
|
||||||
|
'/dashboard/sales/listingvarients': 'listings'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
finance: {
|
||||||
|
key: 'finance',
|
||||||
|
label: 'Finance',
|
||||||
|
iconKey: 'finance',
|
||||||
|
items: financeSidebarItems
|
||||||
|
},
|
||||||
|
management: {
|
||||||
|
key: 'management',
|
||||||
|
label: 'Management',
|
||||||
|
iconKey: 'settings',
|
||||||
|
items: managementSidebarItems
|
||||||
|
},
|
||||||
|
developer: {
|
||||||
|
key: 'developer',
|
||||||
|
label: 'Developer',
|
||||||
|
iconKey: 'developer',
|
||||||
|
items: developerSidebarItems
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const splitPath = (path) => path.split('/').filter(Boolean)
|
||||||
|
|
||||||
|
const isPathPrefixMatch = (candidatePath, pathname) => {
|
||||||
|
const candidateParts = splitPath(candidatePath)
|
||||||
|
const pathParts = splitPath(pathname)
|
||||||
|
if (candidateParts.length > pathParts.length) return false
|
||||||
|
for (let i = 0; i < candidateParts.length; i++) {
|
||||||
|
if (candidateParts[i] !== pathParts[i]) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFilteredItems = (items = [], includeDev = false) =>
|
||||||
|
items
|
||||||
|
.filter((item) => item?.devOnly !== true || includeDev)
|
||||||
|
.map((item) => {
|
||||||
|
if (item?.children && Array.isArray(item.children)) {
|
||||||
|
return { ...item, children: getFilteredItems(item.children, includeDev) }
|
||||||
|
}
|
||||||
|
return { ...item }
|
||||||
|
})
|
||||||
|
|
||||||
|
const flattenPathEntries = (items = [], acc = []) => {
|
||||||
|
items.forEach((item) => {
|
||||||
|
if (item?.type === 'divider') return
|
||||||
|
if (item?.path) {
|
||||||
|
acc.push({ path: item.path, key: item.key })
|
||||||
|
}
|
||||||
|
if (item?.children && Array.isArray(item.children)) {
|
||||||
|
flattenPathEntries(item.children, acc)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return acc
|
||||||
|
}
|
||||||
|
|
||||||
|
const findDefaultKey = (items = []) => {
|
||||||
|
for (const item of items) {
|
||||||
|
if (item?.type === 'divider') continue
|
||||||
|
if (item?.children && item.children.length > 0) {
|
||||||
|
const childKey = findDefaultKey(item.children)
|
||||||
|
if (childKey) return childKey
|
||||||
|
}
|
||||||
|
if (item?.key) return item.key
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const toMenuItems = (items = []) =>
|
||||||
|
items.map((item) => {
|
||||||
|
if (item?.type === 'divider') return { type: 'divider' }
|
||||||
|
|
||||||
|
const menuItem = {
|
||||||
|
key: item.key,
|
||||||
|
label: item.label,
|
||||||
|
iconKey: item.iconKey
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item?.path) {
|
||||||
|
menuItem.path = item.path
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item?.children && Array.isArray(item.children)) {
|
||||||
|
menuItem.children = toMenuItems(item.children)
|
||||||
|
}
|
||||||
|
|
||||||
|
return menuItem
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getSidebar = (sidebarKey) => SIDEBARS[sidebarKey] || null
|
||||||
|
|
||||||
|
export const getSidebarItems = (sidebarKey, options = {}) => {
|
||||||
|
const sidebar = getSidebar(sidebarKey)
|
||||||
|
if (!sidebar) return []
|
||||||
|
const { includeDev = false } = options
|
||||||
|
return getFilteredItems(sidebar.items, includeDev)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getSidebarSelectedKey = (sidebarKey, pathname, options = {}) => {
|
||||||
|
const sidebar = getSidebar(sidebarKey)
|
||||||
|
if (!sidebar) return ''
|
||||||
|
|
||||||
|
const items = getSidebarItems(sidebarKey, options)
|
||||||
|
const pathEntries = flattenPathEntries(items)
|
||||||
|
const aliasEntries = Object.entries(sidebar.routeAliases || {}).map(
|
||||||
|
([path, key]) => ({ path, key })
|
||||||
|
)
|
||||||
|
|
||||||
|
const match = [...pathEntries, ...aliasEntries]
|
||||||
|
.filter((entry) => isPathPrefixMatch(entry.path, pathname))
|
||||||
|
.sort((a, b) => splitPath(b.path).length - splitPath(a.path).length)[0]
|
||||||
|
|
||||||
|
return match?.key || findDefaultKey(items)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getSidebarMenuSections = (options = {}) => {
|
||||||
|
const { includeDev = false } = options
|
||||||
|
return Object.values(SIDEBARS)
|
||||||
|
.filter((sidebar) => includeDev || sidebar.key !== 'developer')
|
||||||
|
.map((sidebar) => ({
|
||||||
|
key: sidebar.key,
|
||||||
|
label: sidebar.label,
|
||||||
|
iconKey: sidebar.iconKey,
|
||||||
|
items: toMenuItems(getSidebarItems(sidebar.key, { includeDev }))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getSidebarDefaultPath = (sidebarKey, options = {}) => {
|
||||||
|
const items = getSidebarItems(sidebarKey, options)
|
||||||
|
const first = flattenPathEntries(items)[0]
|
||||||
|
return first?.path || '/dashboard/production/overview'
|
||||||
|
}
|
||||||
@ -186,14 +186,13 @@ export const Filament = {
|
|||||||
columnWidth: 150,
|
columnWidth: 150,
|
||||||
value: (objectData) => {
|
value: (objectData) => {
|
||||||
const cost = objectData?.cost
|
const cost = objectData?.cost
|
||||||
if (!cost) return undefined
|
if (!cost) return 0
|
||||||
if (objectData?.costTaxRate?.rateType == 'percentage') {
|
if (objectData?.costTaxRate?.rateType == 'percentage') {
|
||||||
return (
|
return (
|
||||||
(cost * (1 + objectData?.costTaxRate?.rate / 100)).toFixed(2) ||
|
(cost * (1 + objectData?.costTaxRate?.rate / 100)).toFixed(2) || 0
|
||||||
undefined
|
|
||||||
)
|
)
|
||||||
} else if (objectData?.costTaxRate?.rateType == 'amount') {
|
} else if (objectData?.costTaxRate?.rateType == 'amount') {
|
||||||
return (cost + objectData?.costTaxRate?.rate).toFixed(2) || undefined
|
return (cost + objectData?.costTaxRate?.rate).toFixed(2) || 0
|
||||||
}
|
}
|
||||||
return cost
|
return cost
|
||||||
}
|
}
|
||||||
|
|||||||
@ -201,11 +201,11 @@ export const FilamentSku = {
|
|||||||
if (!objectData?.overrideCost) return undefined
|
if (!objectData?.overrideCost) return undefined
|
||||||
const cost = objectData?.cost
|
const cost = objectData?.cost
|
||||||
const taxRate = objectData?.costTaxRate
|
const taxRate = objectData?.costTaxRate
|
||||||
if (!cost) return undefined
|
if (!cost) return 0
|
||||||
if (taxRate?.rateType == 'percentage') {
|
if (taxRate?.rateType == 'percentage') {
|
||||||
return (cost * (1 + taxRate?.rate / 100)).toFixed(2) || undefined
|
return (cost * (1 + taxRate?.rate / 100)).toFixed(2) || 0
|
||||||
} else if (taxRate?.rateType == 'amount') {
|
} else if (taxRate?.rateType == 'amount') {
|
||||||
return (cost + taxRate?.rate).toFixed(2) || undefined
|
return (cost + taxRate?.rate).toFixed(2) || 0
|
||||||
}
|
}
|
||||||
return cost
|
return cost
|
||||||
},
|
},
|
||||||
|
|||||||
@ -395,20 +395,19 @@ export const Invoice = {
|
|||||||
columnWidth: 200,
|
columnWidth: 200,
|
||||||
value: (objectData) => {
|
value: (objectData) => {
|
||||||
const invoiceAmount = objectData?.invoiceAmount || 0
|
const invoiceAmount = objectData?.invoiceAmount || 0
|
||||||
|
if (!invoiceAmount) return 0
|
||||||
if (objectData?.taxRate?.rateType == 'percentage') {
|
if (objectData?.taxRate?.rateType == 'percentage') {
|
||||||
return (
|
return (
|
||||||
(invoiceAmount * (1 + objectData?.taxRate?.rate / 100)).toFixed(
|
(invoiceAmount * (1 + objectData?.taxRate?.rate / 100)).toFixed(
|
||||||
2
|
2
|
||||||
) || undefined
|
) || 0
|
||||||
)
|
)
|
||||||
} else if (objectData?.taxRate?.rateType == 'amount') {
|
} else if (objectData?.taxRate?.rateType == 'amount') {
|
||||||
return (
|
return (
|
||||||
(invoiceAmount + objectData?.taxRate?.rate).toFixed(2) ||
|
(invoiceAmount + objectData?.taxRate?.rate).toFixed(2) || 0
|
||||||
undefined
|
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
return invoiceAmount || 0
|
|
||||||
}
|
}
|
||||||
|
return invoiceAmount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -505,20 +504,19 @@ export const Invoice = {
|
|||||||
columnWidth: 200,
|
columnWidth: 200,
|
||||||
value: (objectData) => {
|
value: (objectData) => {
|
||||||
const invoiceAmount = objectData?.invoiceAmount || 0
|
const invoiceAmount = objectData?.invoiceAmount || 0
|
||||||
|
if (!invoiceAmount) return 0
|
||||||
if (objectData?.taxRate?.rateType == 'percentage') {
|
if (objectData?.taxRate?.rateType == 'percentage') {
|
||||||
return (
|
return (
|
||||||
(invoiceAmount * (1 + objectData?.taxRate?.rate / 100)).toFixed(
|
(invoiceAmount * (1 + objectData?.taxRate?.rate / 100)).toFixed(
|
||||||
2
|
2
|
||||||
) || undefined
|
) || 0
|
||||||
)
|
)
|
||||||
} else if (objectData?.taxRate?.rateType == 'amount') {
|
} else if (objectData?.taxRate?.rateType == 'amount') {
|
||||||
return (
|
return (
|
||||||
(invoiceAmount + objectData?.taxRate?.rate).toFixed(2) ||
|
(invoiceAmount + objectData?.taxRate?.rate).toFixed(2) || 0
|
||||||
undefined
|
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
return invoiceAmount || 0
|
|
||||||
}
|
}
|
||||||
|
return invoiceAmount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@ -370,24 +370,20 @@ export const OrderItem = {
|
|||||||
columnWidth: 175,
|
columnWidth: 175,
|
||||||
value: (objectData) => {
|
value: (objectData) => {
|
||||||
const totalAmount = objectData?.itemAmount * objectData?.quantity || 0
|
const totalAmount = objectData?.itemAmount * objectData?.quantity || 0
|
||||||
|
if (!totalAmount) return 0
|
||||||
if (objectData?.taxRate?.rateType == 'percentage') {
|
if (objectData?.taxRate?.rateType == 'percentage') {
|
||||||
if (objectData?.quantity == undefined || objectData?.quantity == 0) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
(
|
(
|
||||||
(totalAmount || 0) *
|
totalAmount *
|
||||||
(1 + objectData?.taxRate?.rate / 100)
|
(1 + objectData?.taxRate?.rate / 100)
|
||||||
).toFixed(2) || undefined
|
).toFixed(2) || 0
|
||||||
)
|
)
|
||||||
} else if (objectData?.taxRate?.rateType == 'amount') {
|
} else if (objectData?.taxRate?.rateType == 'amount') {
|
||||||
return (
|
return (
|
||||||
((totalAmount || 0) + objectData?.taxRate?.rate).toFixed(2) ||
|
(totalAmount + objectData?.taxRate?.rate).toFixed(2) || 0
|
||||||
undefined
|
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
return totalAmount || 0
|
|
||||||
}
|
}
|
||||||
|
return totalAmount
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -155,14 +155,13 @@ export const Part = {
|
|||||||
columnWidth: 150,
|
columnWidth: 150,
|
||||||
value: (objectData) => {
|
value: (objectData) => {
|
||||||
const cost = objectData?.cost
|
const cost = objectData?.cost
|
||||||
if (!cost) return undefined
|
if (!cost) return 0
|
||||||
if (objectData?.costTaxRate?.rateType == 'percentage') {
|
if (objectData?.costTaxRate?.rateType == 'percentage') {
|
||||||
return (
|
return (
|
||||||
(cost * (1 + objectData?.costTaxRate?.rate / 100)).toFixed(2) ||
|
(cost * (1 + objectData?.costTaxRate?.rate / 100)).toFixed(2) || 0
|
||||||
undefined
|
|
||||||
)
|
)
|
||||||
} else if (objectData?.costTaxRate?.rateType == 'amount') {
|
} else if (objectData?.costTaxRate?.rateType == 'amount') {
|
||||||
return (cost + objectData?.costTaxRate?.rate).toFixed(2) || undefined
|
return (cost + objectData?.costTaxRate?.rate).toFixed(2) || 0
|
||||||
}
|
}
|
||||||
return cost
|
return cost
|
||||||
}
|
}
|
||||||
@ -241,16 +240,13 @@ export const Part = {
|
|||||||
} else {
|
} else {
|
||||||
price = objectData?.price
|
price = objectData?.price
|
||||||
}
|
}
|
||||||
if (!price) return undefined
|
if (!price) return 0
|
||||||
if (objectData?.priceTaxRate?.rateType == 'percentage') {
|
if (objectData?.priceTaxRate?.rateType == 'percentage') {
|
||||||
return (
|
return (
|
||||||
(price * (1 + objectData?.priceTaxRate?.rate / 100)).toFixed(2) ||
|
(price * (1 + objectData?.priceTaxRate?.rate / 100)).toFixed(2) || 0
|
||||||
undefined
|
|
||||||
)
|
)
|
||||||
} else if (objectData?.priceTaxRate?.rateType == 'amount') {
|
} else if (objectData?.priceTaxRate?.rateType == 'amount') {
|
||||||
return (
|
return (price + objectData?.priceTaxRate?.rate).toFixed(2) || 0
|
||||||
(price + objectData?.priceTaxRate?.rate).toFixed(2) || undefined
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return price
|
return price
|
||||||
}
|
}
|
||||||
|
|||||||
@ -201,11 +201,11 @@ export const PartSku = {
|
|||||||
if (!objectData?.overrideCost) return undefined
|
if (!objectData?.overrideCost) return undefined
|
||||||
const cost = objectData?.cost
|
const cost = objectData?.cost
|
||||||
const taxRate = objectData?.costTaxRate
|
const taxRate = objectData?.costTaxRate
|
||||||
if (!cost) return undefined
|
if (!cost) return 0
|
||||||
if (taxRate?.rateType == 'percentage') {
|
if (taxRate?.rateType == 'percentage') {
|
||||||
return (cost * (1 + taxRate?.rate / 100)).toFixed(2) || undefined
|
return (cost * (1 + taxRate?.rate / 100)).toFixed(2) || 0
|
||||||
} else if (taxRate?.rateType == 'amount') {
|
} else if (taxRate?.rateType == 'amount') {
|
||||||
return (cost + taxRate?.rate).toFixed(2) || undefined
|
return (cost + taxRate?.rate).toFixed(2) || 0
|
||||||
}
|
}
|
||||||
return cost
|
return cost
|
||||||
},
|
},
|
||||||
@ -276,13 +276,13 @@ export const PartSku = {
|
|||||||
} else {
|
} else {
|
||||||
price = objectData?.price
|
price = objectData?.price
|
||||||
}
|
}
|
||||||
if (price == null) return undefined
|
if (!price) return 0
|
||||||
const taxRate =
|
const taxRate =
|
||||||
objectData?.priceTaxRate ?? objectData?.part?.priceTaxRate
|
objectData?.priceTaxRate ?? objectData?.part?.priceTaxRate
|
||||||
if (taxRate?.rateType == 'percentage') {
|
if (taxRate?.rateType == 'percentage') {
|
||||||
return (price * (1 + taxRate?.rate / 100)).toFixed(2) || undefined
|
return (price * (1 + taxRate?.rate / 100)).toFixed(2) || 0
|
||||||
} else if (taxRate?.rateType == 'amount') {
|
} else if (taxRate?.rateType == 'amount') {
|
||||||
return (price + taxRate?.rate).toFixed(2) || undefined
|
return (price + taxRate?.rate).toFixed(2) || 0
|
||||||
}
|
}
|
||||||
return price
|
return price
|
||||||
},
|
},
|
||||||
|
|||||||
@ -212,11 +212,11 @@ export const ProductSku = {
|
|||||||
if (!objectData?.overrideCost) return undefined
|
if (!objectData?.overrideCost) return undefined
|
||||||
const cost = objectData?.cost
|
const cost = objectData?.cost
|
||||||
const taxRate = objectData?.costTaxRate
|
const taxRate = objectData?.costTaxRate
|
||||||
if (!cost) return undefined
|
if (!cost) return 0
|
||||||
if (taxRate?.rateType == 'percentage') {
|
if (taxRate?.rateType == 'percentage') {
|
||||||
return (cost * (1 + taxRate?.rate / 100)).toFixed(2) || undefined
|
return (cost * (1 + taxRate?.rate / 100)).toFixed(2) || 0
|
||||||
} else if (taxRate?.rateType == 'amount') {
|
} else if (taxRate?.rateType == 'amount') {
|
||||||
return (cost + taxRate?.rate).toFixed(2) || undefined
|
return (cost + taxRate?.rate).toFixed(2) || 0
|
||||||
}
|
}
|
||||||
return cost
|
return cost
|
||||||
},
|
},
|
||||||
@ -289,13 +289,13 @@ export const ProductSku = {
|
|||||||
} else {
|
} else {
|
||||||
price = objectData?.price
|
price = objectData?.price
|
||||||
}
|
}
|
||||||
if (price == null) return undefined
|
if (!price) return 0
|
||||||
const taxRate =
|
const taxRate =
|
||||||
objectData?.priceTaxRate ?? objectData?.product?.priceTaxRate
|
objectData?.priceTaxRate ?? objectData?.product?.priceTaxRate
|
||||||
if (taxRate?.rateType == 'percentage') {
|
if (taxRate?.rateType == 'percentage') {
|
||||||
return (price * (1 + taxRate?.rate / 100)).toFixed(2) || undefined
|
return (price * (1 + taxRate?.rate / 100)).toFixed(2) || 0
|
||||||
} else if (taxRate?.rateType == 'amount') {
|
} else if (taxRate?.rateType == 'amount') {
|
||||||
return (price + taxRate?.rate).toFixed(2) || undefined
|
return (price + taxRate?.rate).toFixed(2) || 0
|
||||||
}
|
}
|
||||||
return price
|
return price
|
||||||
},
|
},
|
||||||
|
|||||||
22
src/database/sidebars/developer.js
Normal file
22
src/database/sidebars/developer.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
const developerSidebarItems = [
|
||||||
|
{
|
||||||
|
key: 'sessionstorage',
|
||||||
|
label: 'Session Storage',
|
||||||
|
iconKey: 'sessionStorage',
|
||||||
|
path: '/dashboard/developer/sessionstorage'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'authcontextdebug',
|
||||||
|
label: 'Auth Debug',
|
||||||
|
iconKey: 'authDebug',
|
||||||
|
path: '/dashboard/developer/authcontextdebug'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'apicontextdebug',
|
||||||
|
label: 'API Debug',
|
||||||
|
iconKey: 'apiDebug',
|
||||||
|
path: '/dashboard/developer/apicontextdebug'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export default developerSidebarItems
|
||||||
23
src/database/sidebars/finance.js
Normal file
23
src/database/sidebars/finance.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
const financeSidebarItems = [
|
||||||
|
{
|
||||||
|
key: 'overview',
|
||||||
|
label: 'Overview',
|
||||||
|
iconKey: 'finance',
|
||||||
|
path: '/dashboard/finance/overview'
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
key: 'invoices',
|
||||||
|
label: 'Invoices',
|
||||||
|
iconKey: 'invoice',
|
||||||
|
path: '/dashboard/finance/invoices'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'payments',
|
||||||
|
label: 'Payments',
|
||||||
|
iconKey: 'payment',
|
||||||
|
path: '/dashboard/finance/payments'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export default financeSidebarItems
|
||||||
74
src/database/sidebars/inventory.js
Normal file
74
src/database/sidebars/inventory.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
const inventorySidebarItems = [
|
||||||
|
{
|
||||||
|
key: 'overview',
|
||||||
|
label: 'Overview',
|
||||||
|
iconKey: 'inventory',
|
||||||
|
path: '/dashboard/inventory/overview'
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
key: 'filamentstocks',
|
||||||
|
label: 'Filament Stocks',
|
||||||
|
iconKey: 'filamentStock',
|
||||||
|
path: '/dashboard/inventory/filamentstocks'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'partstocks',
|
||||||
|
label: 'Part Stocks',
|
||||||
|
iconKey: 'partStock',
|
||||||
|
path: '/dashboard/inventory/partstocks'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'productstocks',
|
||||||
|
label: 'Product Stocks',
|
||||||
|
iconKey: 'productStock',
|
||||||
|
path: '/dashboard/inventory/productstocks'
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
key: 'purchaseorders',
|
||||||
|
label: 'Purchase Orders',
|
||||||
|
iconKey: 'purchaseOrder',
|
||||||
|
path: '/dashboard/inventory/purchaseorders'
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
key: 'orderitems',
|
||||||
|
label: 'Order Items',
|
||||||
|
iconKey: 'orderItem',
|
||||||
|
path: '/dashboard/inventory/orderitems'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'shipments',
|
||||||
|
label: 'Shipments',
|
||||||
|
iconKey: 'shipment',
|
||||||
|
path: '/dashboard/inventory/shipments'
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
key: 'stocklocations',
|
||||||
|
label: 'Stock Locations',
|
||||||
|
iconKey: 'stockLocation',
|
||||||
|
path: '/dashboard/inventory/stocklocations'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'stockevents',
|
||||||
|
label: 'Stock Events',
|
||||||
|
iconKey: 'stockEvent',
|
||||||
|
path: '/dashboard/inventory/stockevents'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'stockaudits',
|
||||||
|
label: 'Stock Audits',
|
||||||
|
iconKey: 'stockAudit',
|
||||||
|
path: '/dashboard/inventory/stockaudits'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'stocktransfers',
|
||||||
|
label: 'Stock Transfers',
|
||||||
|
iconKey: 'stockTransfer',
|
||||||
|
path: '/dashboard/inventory/stocktransfers'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export default inventorySidebarItems
|
||||||
168
src/database/sidebars/management.js
Normal file
168
src/database/sidebars/management.js
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
const managementSidebarItems = [
|
||||||
|
{
|
||||||
|
key: 'filaments',
|
||||||
|
iconKey: 'filament',
|
||||||
|
label: 'Filaments',
|
||||||
|
path: '/dashboard/management/filaments'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'filamentSkus',
|
||||||
|
iconKey: 'filamentSku',
|
||||||
|
label: 'Filament SKUs',
|
||||||
|
path: '/dashboard/management/filamentskus'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'parts',
|
||||||
|
iconKey: 'part',
|
||||||
|
label: 'Parts',
|
||||||
|
path: '/dashboard/management/parts'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'partSkus',
|
||||||
|
iconKey: 'partSku',
|
||||||
|
label: 'Part SKUs',
|
||||||
|
path: '/dashboard/management/partskus'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'products',
|
||||||
|
iconKey: 'product',
|
||||||
|
label: 'Products',
|
||||||
|
path: '/dashboard/management/products'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'productCategories',
|
||||||
|
iconKey: 'productCategory',
|
||||||
|
label: 'Product Categories',
|
||||||
|
path: '/dashboard/management/productcategories'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'productSkus',
|
||||||
|
iconKey: 'productSku',
|
||||||
|
label: 'Product SKUs',
|
||||||
|
path: '/dashboard/management/productskus'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'vendors',
|
||||||
|
iconKey: 'vendor',
|
||||||
|
label: 'Vendors',
|
||||||
|
path: '/dashboard/management/vendors'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'materials',
|
||||||
|
iconKey: 'material',
|
||||||
|
label: 'Materials',
|
||||||
|
path: '/dashboard/management/materials'
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
key: 'couriers',
|
||||||
|
iconKey: 'courier',
|
||||||
|
label: 'Couriers',
|
||||||
|
path: '/dashboard/management/couriers'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'courierServices',
|
||||||
|
iconKey: 'courierService',
|
||||||
|
label: 'Courier Services',
|
||||||
|
path: '/dashboard/management/courierservices'
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
key: 'taxRates',
|
||||||
|
iconKey: 'taxRate',
|
||||||
|
label: 'Tax Rates',
|
||||||
|
path: '/dashboard/management/taxrates'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'taxRecords',
|
||||||
|
iconKey: 'taxRecord',
|
||||||
|
label: 'Tax Records',
|
||||||
|
path: '/dashboard/management/taxrecords'
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
key: 'noteTypes',
|
||||||
|
iconKey: 'noteType',
|
||||||
|
label: 'Note Types',
|
||||||
|
path: '/dashboard/management/notetypes'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'documents',
|
||||||
|
iconKey: 'document',
|
||||||
|
label: 'Documents',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
key: 'documentPrinters',
|
||||||
|
iconKey: 'documentPrinter',
|
||||||
|
label: 'Document Printers',
|
||||||
|
path: '/dashboard/management/documentprinters'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'documentJobs',
|
||||||
|
iconKey: 'documentJob',
|
||||||
|
label: 'Document Jobs',
|
||||||
|
path: '/dashboard/management/documentjobs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'documentTemplates',
|
||||||
|
iconKey: 'documentTemplate',
|
||||||
|
label: 'Document Templates',
|
||||||
|
path: '/dashboard/management/documenttemplates'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'documentSizes',
|
||||||
|
iconKey: 'documentSize',
|
||||||
|
label: 'Document Sizes',
|
||||||
|
path: '/dashboard/management/documentsizes'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
key: 'hosts',
|
||||||
|
iconKey: 'host',
|
||||||
|
label: 'Hosts',
|
||||||
|
path: '/dashboard/management/hosts'
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
key: 'users',
|
||||||
|
iconKey: 'person',
|
||||||
|
label: 'Users',
|
||||||
|
path: '/dashboard/management/users'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'appPasswords',
|
||||||
|
iconKey: 'appPassword',
|
||||||
|
label: 'App Passwords',
|
||||||
|
path: '/dashboard/management/apppasswords'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'settings',
|
||||||
|
iconKey: 'settings',
|
||||||
|
label: 'Settings',
|
||||||
|
path: '/dashboard/management/settings'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'files',
|
||||||
|
iconKey: 'file',
|
||||||
|
label: 'Files',
|
||||||
|
path: '/dashboard/management/files'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'auditLogs',
|
||||||
|
iconKey: 'auditLog',
|
||||||
|
label: 'Audit Logs',
|
||||||
|
path: '/dashboard/management/auditlogs'
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
key: 'developer',
|
||||||
|
iconKey: 'developer',
|
||||||
|
label: 'Developer',
|
||||||
|
path: '/dashboard/developer/sessionstorage',
|
||||||
|
devOnly: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export default managementSidebarItems
|
||||||
35
src/database/sidebars/production.js
Normal file
35
src/database/sidebars/production.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
const productionSidebarItems = [
|
||||||
|
{
|
||||||
|
key: 'overview',
|
||||||
|
iconKey: 'production',
|
||||||
|
label: 'Overview',
|
||||||
|
path: '/dashboard/production/overview'
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
key: 'printers',
|
||||||
|
iconKey: 'printer',
|
||||||
|
label: 'Printers',
|
||||||
|
path: '/dashboard/production/printers'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'jobs',
|
||||||
|
iconKey: 'job',
|
||||||
|
label: 'Jobs',
|
||||||
|
path: '/dashboard/production/jobs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'subJobs',
|
||||||
|
iconKey: 'subJob',
|
||||||
|
label: 'Sub Jobs',
|
||||||
|
path: '/dashboard/production/subjobs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'gcodeFiles',
|
||||||
|
iconKey: 'gcodeFile',
|
||||||
|
label: 'GCode Files',
|
||||||
|
path: '/dashboard/production/gcodefiles'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export default productionSidebarItems
|
||||||
35
src/database/sidebars/sales.js
Normal file
35
src/database/sidebars/sales.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
const salesSidebarItems = [
|
||||||
|
{
|
||||||
|
key: 'overview',
|
||||||
|
label: 'Overview',
|
||||||
|
iconKey: 'sales',
|
||||||
|
path: '/dashboard/sales/overview'
|
||||||
|
},
|
||||||
|
{ type: 'divider' },
|
||||||
|
{
|
||||||
|
key: 'clients',
|
||||||
|
label: 'Clients',
|
||||||
|
iconKey: 'client',
|
||||||
|
path: '/dashboard/sales/clients'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'salesorders',
|
||||||
|
label: 'Sales Orders',
|
||||||
|
iconKey: 'salesOrder',
|
||||||
|
path: '/dashboard/sales/salesorders'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'marketplaces',
|
||||||
|
label: 'Marketplaces',
|
||||||
|
iconKey: 'marketplace',
|
||||||
|
path: '/dashboard/sales/marketplaces'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'listings',
|
||||||
|
label: 'Listings',
|
||||||
|
iconKey: 'listing',
|
||||||
|
path: '/dashboard/sales/listings'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export default salesSidebarItems
|
||||||
Loading…
x
Reference in New Issue
Block a user