@@ -52,12 +52,6 @@ const DashboardOverview = () => {
{/* Overview Metrics */}
-
{
subtitle={`${salesData.overview.voided_orders} voided, ${salesData.overview.refunded_orders} refunded`}
bgColor='bg-blue-500'
/>
+
{
function formatMetricName(metric: string): string {
const nameMap: { [key: string]: string } = {
revenue: 'Revenue',
- net_profit: 'Net Profit',
+ net_profit: 'Net Profit'
}
return nameMap[metric] || metric.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())
@@ -61,15 +61,25 @@ const DashboardProfitloss = () => {
]
}
- const MetricCard = ({ iconClass, title, value, subtitle, bgColor = 'bg-blue-500', isNegative = false }: any) => (
+ const MetricCard = ({
+ iconClass,
+ title,
+ value,
+ subtitle,
+ bgColor = 'bg-blue-500',
+ isNegative = false,
+ isCurrency = false
+ }: any) => (
{title}
-
{value}
+
+ {isCurrency ? 'Rp ' + value : value}
+
{subtitle &&
{subtitle}
}
-
@@ -95,12 +105,14 @@ const DashboardProfitloss = () => {
title='Total Revenue'
value={formatShortCurrency(profitData.summary.total_revenue)}
bgColor='bg-green-500'
+ isCurrency={true}
/>
{
subtitle={`Margin: ${formatPercentage(profitData.summary.gross_profit_margin)}`}
bgColor='bg-blue-500'
isNegative={profitData.summary.gross_profit < 0}
+ isCurrency={true}
/>
{
Net Profit
- {formatShortCurrency(profitData.summary.net_profit)}
+ Rp {formatShortCurrency(profitData.summary.net_profit)}
Margin: {formatPercentage(profitData.summary.net_profit_margin)}
@@ -144,7 +157,7 @@ const DashboardProfitloss = () => {
Tax & Discount
- {formatShortCurrency(profitData.summary.total_tax + profitData.summary.total_discount)}
+ Rp {formatShortCurrency(profitData.summary.total_tax + profitData.summary.total_discount)}
Tax: {formatShortCurrency(profitData.summary.total_tax)} | Discount:{' '}
diff --git a/src/components/layout/vertical/VerticalMenu.tsx b/src/components/layout/vertical/VerticalMenu.tsx
index c47bc40..5002fe6 100644
--- a/src/components/layout/vertical/VerticalMenu.tsx
+++ b/src/components/layout/vertical/VerticalMenu.tsx
@@ -90,7 +90,7 @@ const VerticalMenu = ({ dictionary, scrollMenu }: Props) => {
- }>
+ }>
{/* */}
diff --git a/src/data/dictionaries/ar.json b/src/data/dictionaries/ar.json
index c99d8e2..b005a82 100644
--- a/src/data/dictionaries/ar.json
+++ b/src/data/dictionaries/ar.json
@@ -2,7 +2,7 @@
"navigation": {
"dashboards": "لوحات القيادة",
"analytics": "تحليلات",
- "eCommerce": "التجارة الإلكترونية",
+ "eCommerce": "تجزئة الكترونية",
"stock": "المخزون",
"academy": "أكاديمية",
"logistics": "اللوجستية",
diff --git a/src/data/dictionaries/en.json b/src/data/dictionaries/en.json
index 18771ed..47b8b99 100644
--- a/src/data/dictionaries/en.json
+++ b/src/data/dictionaries/en.json
@@ -2,7 +2,7 @@
"navigation": {
"dashboards": "Dashboards",
"analytics": "Analytics",
- "eCommerce": "eCommerce",
+ "eCommerce": "Inventory",
"stock": "Stock",
"academy": "Academy",
"logistics": "Logistics",
diff --git a/src/data/dictionaries/fr.json b/src/data/dictionaries/fr.json
index 3215e14..6f8786a 100644
--- a/src/data/dictionaries/fr.json
+++ b/src/data/dictionaries/fr.json
@@ -2,7 +2,7 @@
"navigation": {
"dashboards": "Tableaux de bord",
"analytics": "Analytique",
- "eCommerce": "commerce électronique",
+ "eCommerce": "Inventaire",
"stock": "Stock",
"academy": "Académie",
"logistics": "Logistique",
diff --git a/src/redux-store/slices/product.ts b/src/redux-store/slices/product.ts
index 9b2ec59..af9df26 100644
--- a/src/redux-store/slices/product.ts
+++ b/src/redux-store/slices/product.ts
@@ -13,7 +13,6 @@ const initialState: { productRequest: ProductRequest } = {
sku: '',
name: '',
description: '',
- barcode: '',
price: 0,
cost: 0,
printer_type: '',
diff --git a/src/redux-store/slices/productRecipe.ts b/src/redux-store/slices/productRecipe.ts
index 5dc1c7a..de89da4 100644
--- a/src/redux-store/slices/productRecipe.ts
+++ b/src/redux-store/slices/productRecipe.ts
@@ -1,20 +1,71 @@
// Third-party Imports
import type { PayloadAction } from '@reduxjs/toolkit'
import { createSlice } from '@reduxjs/toolkit'
+import { ProductRecipe } from '../../types/services/productRecipe'
// Type Imports
// Data Imports
-const initialState: { currentProductRecipe: any } = {
- currentProductRecipe: {}
+const initialState: { currentVariant: any, currentProductRecipe: ProductRecipe } = {
+ currentVariant: {},
+ currentProductRecipe: {
+ id: '',
+ organization_id: '',
+ outlet_id: null,
+ product_id: '',
+ variant_id: null,
+ ingredient_id: '',
+ quantity: 0,
+ created_at: '',
+ updated_at: '',
+ product: {
+ ID: '',
+ OrganizationID: '',
+ CategoryID: '',
+ SKU: '',
+ Name: '',
+ Description: null,
+ Price: 0,
+ Cost: 0,
+ BusinessType: '',
+ ImageURL: '',
+ PrinterType: '',
+ UnitID: null,
+ HasIngredients: false,
+ Metadata: {},
+ IsActive: false,
+ CreatedAt: '',
+ UpdatedAt: ''
+ },
+ ingredient: {
+ id: '',
+ organization_id: '',
+ outlet_id: null,
+ name: '',
+ unit_id: '',
+ cost: 0,
+ stock: 0,
+ is_semi_finished: false,
+ is_active: false,
+ metadata: {},
+ created_at: '',
+ updated_at: ''
+ }
+ }
}
export const productRecipeSlice = createSlice({
name: 'productRecipe',
initialState,
reducers: {
- setProductRecipe: (state, action: PayloadAction) => {
+ setProductVariant: (state, action: PayloadAction) => {
+ state.currentVariant = action.payload
+ },
+ resetProductVariant: state => {
+ state.currentVariant = initialState.currentVariant
+ },
+ setProductRecipe: (state, action: PayloadAction) => {
state.currentProductRecipe = action.payload
},
resetProductRecipe: state => {
@@ -23,6 +74,6 @@ export const productRecipeSlice = createSlice({
}
})
-export const { setProductRecipe, resetProductRecipe } = productRecipeSlice.actions
+export const { setProductVariant, resetProductVariant, setProductRecipe, resetProductRecipe } = productRecipeSlice.actions
export default productRecipeSlice.reducer
diff --git a/src/services/mutations/productRecipes.ts b/src/services/mutations/productRecipes.ts
index 4ccf3de..fbd428d 100644
--- a/src/services/mutations/productRecipes.ts
+++ b/src/services/mutations/productRecipes.ts
@@ -38,8 +38,23 @@ export const useProductRecipesMutation = () => {
}
})
+ const deleteProductRecipe = useMutation({
+ mutationFn: async (id: string) => {
+ const response = await api.delete(`/product-recipes/${id}`)
+ return response.data
+ },
+ onSuccess: () => {
+ toast.success('Product Recipe deleted successfully!')
+ queryClient.invalidateQueries({ queryKey: ['product-recipes'] })
+ },
+ onError: (error: any) => {
+ toast.error(error.response?.data?.errors?.[0]?.cause || 'Delete failed')
+ }
+ })
+
return {
createProductRecipe,
- updateProductRecipe
+ updateProductRecipe,
+ deleteProductRecipe
}
}
diff --git a/src/services/queries/products.ts b/src/services/queries/products.ts
index c2cf7c8..93ea235 100644
--- a/src/services/queries/products.ts
+++ b/src/services/queries/products.ts
@@ -1,15 +1,14 @@
import { useQuery } from '@tanstack/react-query'
import { Product, Products } from '../../types/services/product'
import { api } from '../api'
-import { ProductRecipe } from '../../types/services/productRecipe'
-interface ProductsQueryParams {
+export interface ProductsQueryParams {
page?: number
limit?: number
search?: string
// Add other filter parameters as needed
category_id?: string
- is_active?: boolean
+ is_active?: boolean | string
}
export function useProducts(params: ProductsQueryParams = {}) {
diff --git a/src/types/services/inventory.ts b/src/types/services/inventory.ts
index 4f5f0d8..7d22234 100644
--- a/src/types/services/inventory.ts
+++ b/src/types/services/inventory.ts
@@ -13,6 +13,7 @@ export interface Inventory {
quantity: number
reorder_level: number
is_low_stock: boolean
+ product: any
updated_at: string // ISO 8601 timestamp
}
diff --git a/src/types/services/product.ts b/src/types/services/product.ts
index bb7002d..0cc3f8e 100644
--- a/src/types/services/product.ts
+++ b/src/types/services/product.ts
@@ -47,7 +47,6 @@ export type ProductRequest = {
sku: string
name: string
description: string
- barcode: string
price: number
cost: number
printer_type: string
diff --git a/src/views/Login.tsx b/src/views/Login.tsx
index 9be34de..75bbe6e 100644
--- a/src/views/Login.tsx
+++ b/src/views/Login.tsx
@@ -133,11 +133,22 @@ const Login = ({ mode }: { mode: SystemMode }) => {
const handleClickShowPassword = () => setIsPasswordShown(show => !show)
const onSubmit: SubmitHandler = async (data: FormData) => {
- login.mutate(data)
+ login.mutate(data, {
+ onSuccess: (data: any) => {
+ if (data?.user?.role === 'admin') {
+ const redirectURL = searchParams.get('redirectTo') ?? '/dashboards/overview'
- const redirectURL = searchParams.get('redirectTo') ?? '/dashboards/overview'
+ router.replace(getLocalizedUrl(redirectURL, locale as Locale))
+ } else {
+ const redirectURL = searchParams.get('redirectTo') ?? '/sa/organizations/list'
- router.replace(getLocalizedUrl(redirectURL, locale as Locale))
+ router.replace(getLocalizedUrl(redirectURL, locale as Locale))
+ }
+ },
+ onError: (error: any) => {
+ setErrorState(error.response.data)
+ }
+ })
}
return (
@@ -243,7 +254,11 @@ const Login = ({ mode }: { mode: SystemMode }) => {
New on our platform?
-
+
Create an account
diff --git a/src/views/NotFound.tsx b/src/views/NotFound.tsx
index b335aa7..e34e573 100644
--- a/src/views/NotFound.tsx
+++ b/src/views/NotFound.tsx
@@ -17,6 +17,7 @@ import type { SystemMode } from '@core/types'
// Hook Imports
import { useImageVariant } from '@core/hooks/useImageVariant'
+import { useAuth } from '../contexts/authContext'
// Styled Components
const MaskImg = styled('img')({
@@ -29,6 +30,8 @@ const MaskImg = styled('img')({
})
const NotFound = ({ mode }: { mode: SystemMode }) => {
+ const { currentUser } = useAuth()
+
// Vars
const darkImg = '/images/pages/misc-mask-dark.png'
const lightImg = '/images/pages/misc-mask-light.png'
@@ -48,7 +51,11 @@ const NotFound = ({ mode }: { mode: SystemMode }) => {
Page Not Found ⚠️
we couldn't find the page you are looking for.