Layout tweaksÏ
This commit is contained in:
@@ -66,7 +66,7 @@ export function CalculationSettings() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="max-w-[700px] space-y-4">
|
||||||
{/* Sales Velocity Configuration Card */}
|
{/* Sales Velocity Configuration Card */}
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
|||||||
@@ -1,630 +0,0 @@
|
|||||||
import { useState, useEffect } from 'react';
|
|
||||||
import { Button } from "@/components/ui/button";
|
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
|
||||||
import { Input } from "@/components/ui/input";
|
|
||||||
import { Label } from "@/components/ui/label";
|
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
||||||
import { toast } from "sonner";
|
|
||||||
import config from '../../config';
|
|
||||||
|
|
||||||
interface StockThreshold {
|
|
||||||
id: number;
|
|
||||||
category_id: number | null;
|
|
||||||
vendor: string | null;
|
|
||||||
critical_days: number;
|
|
||||||
reorder_days: number;
|
|
||||||
overstock_days: number;
|
|
||||||
low_stock_threshold: number;
|
|
||||||
min_reorder_quantity: number;
|
|
||||||
category_name?: string;
|
|
||||||
threshold_scope?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface LeadTimeThreshold {
|
|
||||||
id: number;
|
|
||||||
category_id: number | null;
|
|
||||||
vendor: string | null;
|
|
||||||
target_days: number;
|
|
||||||
warning_days: number;
|
|
||||||
critical_days: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SalesVelocityConfig {
|
|
||||||
id: number;
|
|
||||||
category_id: number | null;
|
|
||||||
vendor: string | null;
|
|
||||||
daily_window_days: number;
|
|
||||||
weekly_window_days: number;
|
|
||||||
monthly_window_days: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ABCClassificationConfig {
|
|
||||||
id: number;
|
|
||||||
a_threshold: number;
|
|
||||||
b_threshold: number;
|
|
||||||
classification_period_days: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SafetyStockConfig {
|
|
||||||
id: number;
|
|
||||||
category_id: number | null;
|
|
||||||
vendor: string | null;
|
|
||||||
coverage_days: number;
|
|
||||||
service_level: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TurnoverConfig {
|
|
||||||
id: number;
|
|
||||||
category_id: number | null;
|
|
||||||
vendor: string | null;
|
|
||||||
calculation_period_days: number;
|
|
||||||
target_rate: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Configuration() {
|
|
||||||
const [stockThresholds, setStockThresholds] = useState<StockThreshold>({
|
|
||||||
id: 1,
|
|
||||||
category_id: null,
|
|
||||||
vendor: null,
|
|
||||||
critical_days: 7,
|
|
||||||
reorder_days: 14,
|
|
||||||
overstock_days: 90,
|
|
||||||
low_stock_threshold: 5,
|
|
||||||
min_reorder_quantity: 1
|
|
||||||
});
|
|
||||||
|
|
||||||
const [leadTimeThresholds, setLeadTimeThresholds] = useState<LeadTimeThreshold>({
|
|
||||||
id: 1,
|
|
||||||
category_id: null,
|
|
||||||
vendor: null,
|
|
||||||
target_days: 14,
|
|
||||||
warning_days: 21,
|
|
||||||
critical_days: 30
|
|
||||||
});
|
|
||||||
|
|
||||||
const [salesVelocityConfig, setSalesVelocityConfig] = useState<SalesVelocityConfig>({
|
|
||||||
id: 1,
|
|
||||||
category_id: null,
|
|
||||||
vendor: null,
|
|
||||||
daily_window_days: 30,
|
|
||||||
weekly_window_days: 7,
|
|
||||||
monthly_window_days: 90
|
|
||||||
});
|
|
||||||
|
|
||||||
const [abcConfig, setAbcConfig] = useState<ABCClassificationConfig>({
|
|
||||||
id: 1,
|
|
||||||
a_threshold: 20.0,
|
|
||||||
b_threshold: 50.0,
|
|
||||||
classification_period_days: 90
|
|
||||||
});
|
|
||||||
|
|
||||||
const [safetyStockConfig, setSafetyStockConfig] = useState<SafetyStockConfig>({
|
|
||||||
id: 1,
|
|
||||||
category_id: null,
|
|
||||||
vendor: null,
|
|
||||||
coverage_days: 14,
|
|
||||||
service_level: 95.0
|
|
||||||
});
|
|
||||||
|
|
||||||
const [turnoverConfig, setTurnoverConfig] = useState<TurnoverConfig>({
|
|
||||||
id: 1,
|
|
||||||
category_id: null,
|
|
||||||
vendor: null,
|
|
||||||
calculation_period_days: 30,
|
|
||||||
target_rate: 1.0
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const loadConfig = async () => {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${config.apiUrl}/config`, {
|
|
||||||
credentials: 'include'
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to load configuration');
|
|
||||||
}
|
|
||||||
const data = await response.json();
|
|
||||||
setStockThresholds(data.stockThresholds);
|
|
||||||
setLeadTimeThresholds(data.leadTimeThresholds);
|
|
||||||
setSalesVelocityConfig(data.salesVelocityConfig);
|
|
||||||
setAbcConfig(data.abcConfig);
|
|
||||||
setSafetyStockConfig(data.safetyStockConfig);
|
|
||||||
setTurnoverConfig(data.turnoverConfig);
|
|
||||||
} catch (error) {
|
|
||||||
toast.error(`Failed to load configuration: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
loadConfig();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleUpdateStockThresholds = async () => {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${config.apiUrl}/config/stock-thresholds/1`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
credentials: 'include',
|
|
||||||
body: JSON.stringify(stockThresholds)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const data = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(data.error || 'Failed to update stock thresholds');
|
|
||||||
}
|
|
||||||
|
|
||||||
toast.success('Stock thresholds updated successfully');
|
|
||||||
} catch (error) {
|
|
||||||
toast.error(`Failed to update thresholds: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUpdateLeadTimeThresholds = async () => {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${config.apiUrl}/config/lead-time-thresholds/1`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
credentials: 'include',
|
|
||||||
body: JSON.stringify(leadTimeThresholds)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const data = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(data.error || 'Failed to update lead time thresholds');
|
|
||||||
}
|
|
||||||
|
|
||||||
toast.success('Lead time thresholds updated successfully');
|
|
||||||
} catch (error) {
|
|
||||||
toast.error(`Failed to update thresholds: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUpdateSalesVelocityConfig = async () => {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${config.apiUrl}/config/sales-velocity/1`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
credentials: 'include',
|
|
||||||
body: JSON.stringify(salesVelocityConfig)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const data = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(data.error || 'Failed to update sales velocity configuration');
|
|
||||||
}
|
|
||||||
|
|
||||||
toast.success('Sales velocity configuration updated successfully');
|
|
||||||
} catch (error) {
|
|
||||||
toast.error(`Failed to update configuration: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUpdateABCConfig = async () => {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${config.apiUrl}/config/abc-classification/1`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
credentials: 'include',
|
|
||||||
body: JSON.stringify(abcConfig)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const data = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(data.error || 'Failed to update ABC classification configuration');
|
|
||||||
}
|
|
||||||
|
|
||||||
toast.success('ABC classification configuration updated successfully');
|
|
||||||
} catch (error) {
|
|
||||||
toast.error(`Failed to update configuration: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUpdateSafetyStockConfig = async () => {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${config.apiUrl}/config/safety-stock/1`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
credentials: 'include',
|
|
||||||
body: JSON.stringify(safetyStockConfig)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const data = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(data.error || 'Failed to update safety stock configuration');
|
|
||||||
}
|
|
||||||
|
|
||||||
toast.success('Safety stock configuration updated successfully');
|
|
||||||
} catch (error) {
|
|
||||||
toast.error(`Failed to update configuration: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUpdateTurnoverConfig = async () => {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`${config.apiUrl}/config/turnover/1`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
credentials: 'include',
|
|
||||||
body: JSON.stringify(turnoverConfig)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
const data = await response.json().catch(() => ({}));
|
|
||||||
throw new Error(data.error || 'Failed to update turnover configuration');
|
|
||||||
}
|
|
||||||
|
|
||||||
toast.success('Turnover configuration updated successfully');
|
|
||||||
} catch (error) {
|
|
||||||
toast.error(`Failed to update configuration: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tabs defaultValue="stock" className="w-full">
|
|
||||||
<TabsList>
|
|
||||||
<TabsTrigger value="stock">Stock Management</TabsTrigger>
|
|
||||||
<TabsTrigger value="performance">Performance Metrics</TabsTrigger>
|
|
||||||
<TabsTrigger value="calculation">Calculation Settings</TabsTrigger>
|
|
||||||
</TabsList>
|
|
||||||
|
|
||||||
<TabsContent value="stock" className="space-y-4">
|
|
||||||
{/* Stock Thresholds Card */}
|
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>Stock Thresholds</CardTitle>
|
|
||||||
<CardDescription>Configure stock level thresholds for inventory management</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="critical-days">Critical Days</Label>
|
|
||||||
<Input
|
|
||||||
id="critical-days"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
value={stockThresholds.critical_days}
|
|
||||||
onChange={(e) => setStockThresholds(prev => ({
|
|
||||||
...prev,
|
|
||||||
critical_days: parseInt(e.target.value) || 1
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="reorder-days">Reorder Days</Label>
|
|
||||||
<Input
|
|
||||||
id="reorder-days"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
value={stockThresholds.reorder_days}
|
|
||||||
onChange={(e) => setStockThresholds(prev => ({
|
|
||||||
...prev,
|
|
||||||
reorder_days: parseInt(e.target.value) || 1
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="overstock-days">Overstock Days</Label>
|
|
||||||
<Input
|
|
||||||
id="overstock-days"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
value={stockThresholds.overstock_days}
|
|
||||||
onChange={(e) => setStockThresholds(prev => ({
|
|
||||||
...prev,
|
|
||||||
overstock_days: parseInt(e.target.value) || 1
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="low-stock-threshold">Low Stock Threshold</Label>
|
|
||||||
<Input
|
|
||||||
id="low-stock-threshold"
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
value={stockThresholds.low_stock_threshold}
|
|
||||||
onChange={(e) => setStockThresholds(prev => ({
|
|
||||||
...prev,
|
|
||||||
low_stock_threshold: parseInt(e.target.value) || 0
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="min-reorder-quantity">Minimum Reorder Quantity</Label>
|
|
||||||
<Input
|
|
||||||
id="min-reorder-quantity"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
value={stockThresholds.min_reorder_quantity}
|
|
||||||
onChange={(e) => setStockThresholds(prev => ({
|
|
||||||
...prev,
|
|
||||||
min_reorder_quantity: parseInt(e.target.value) || 1
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Button onClick={handleUpdateStockThresholds}>
|
|
||||||
Update Stock Thresholds
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Safety Stock Configuration Card */}
|
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>Safety Stock</CardTitle>
|
|
||||||
<CardDescription>Configure safety stock parameters</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="coverage-days">Coverage Days</Label>
|
|
||||||
<Input
|
|
||||||
id="coverage-days"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
value={safetyStockConfig.coverage_days}
|
|
||||||
onChange={(e) => setSafetyStockConfig(prev => ({
|
|
||||||
...prev,
|
|
||||||
coverage_days: parseInt(e.target.value) || 1
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="service-level">Service Level (%)</Label>
|
|
||||||
<Input
|
|
||||||
id="service-level"
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
max="100"
|
|
||||||
step="0.1"
|
|
||||||
value={safetyStockConfig.service_level}
|
|
||||||
onChange={(e) => setSafetyStockConfig(prev => ({
|
|
||||||
...prev,
|
|
||||||
service_level: parseFloat(e.target.value) || 0
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Button onClick={handleUpdateSafetyStockConfig}>
|
|
||||||
Update Safety Stock Configuration
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</TabsContent>
|
|
||||||
|
|
||||||
<TabsContent value="performance" className="space-y-4">
|
|
||||||
{/* Lead Time Thresholds Card */}
|
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>Lead Time Thresholds</CardTitle>
|
|
||||||
<CardDescription>Configure lead time thresholds for vendor performance</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="grid grid-cols-3 gap-4">
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="target-days">Target Days</Label>
|
|
||||||
<Input
|
|
||||||
id="target-days"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
value={leadTimeThresholds.target_days}
|
|
||||||
onChange={(e) => setLeadTimeThresholds(prev => ({
|
|
||||||
...prev,
|
|
||||||
target_days: parseInt(e.target.value) || 1
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="warning-days">Warning Days</Label>
|
|
||||||
<Input
|
|
||||||
id="warning-days"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
value={leadTimeThresholds.warning_days}
|
|
||||||
onChange={(e) => setLeadTimeThresholds(prev => ({
|
|
||||||
...prev,
|
|
||||||
warning_days: parseInt(e.target.value) || 1
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="critical-days-lead">Critical Days</Label>
|
|
||||||
<Input
|
|
||||||
id="critical-days-lead"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
value={leadTimeThresholds.critical_days}
|
|
||||||
onChange={(e) => setLeadTimeThresholds(prev => ({
|
|
||||||
...prev,
|
|
||||||
critical_days: parseInt(e.target.value) || 1
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Button onClick={handleUpdateLeadTimeThresholds}>
|
|
||||||
Update Lead Time Thresholds
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* ABC Classification Card */}
|
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>ABC Classification</CardTitle>
|
|
||||||
<CardDescription>Configure ABC classification parameters</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="grid grid-cols-3 gap-4">
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="a-threshold">A Threshold (%)</Label>
|
|
||||||
<Input
|
|
||||||
id="a-threshold"
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
max="100"
|
|
||||||
step="0.1"
|
|
||||||
value={abcConfig.a_threshold}
|
|
||||||
onChange={(e) => setAbcConfig(prev => ({
|
|
||||||
...prev,
|
|
||||||
a_threshold: parseFloat(e.target.value) || 0
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="b-threshold">B Threshold (%)</Label>
|
|
||||||
<Input
|
|
||||||
id="b-threshold"
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
max="100"
|
|
||||||
step="0.1"
|
|
||||||
value={abcConfig.b_threshold}
|
|
||||||
onChange={(e) => setAbcConfig(prev => ({
|
|
||||||
...prev,
|
|
||||||
b_threshold: parseFloat(e.target.value) || 0
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="classification-period">Classification Period (days)</Label>
|
|
||||||
<Input
|
|
||||||
id="classification-period"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
value={abcConfig.classification_period_days}
|
|
||||||
onChange={(e) => setAbcConfig(prev => ({
|
|
||||||
...prev,
|
|
||||||
classification_period_days: parseInt(e.target.value) || 1
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Button onClick={handleUpdateABCConfig}>
|
|
||||||
Update ABC Classification
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Turnover Configuration Card */}
|
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>Turnover Rate</CardTitle>
|
|
||||||
<CardDescription>Configure turnover rate calculations</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="calculation-period">Calculation Period (days)</Label>
|
|
||||||
<Input
|
|
||||||
id="calculation-period"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
value={turnoverConfig.calculation_period_days}
|
|
||||||
onChange={(e) => setTurnoverConfig(prev => ({
|
|
||||||
...prev,
|
|
||||||
calculation_period_days: parseInt(e.target.value) || 1
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="target-rate">Target Rate</Label>
|
|
||||||
<Input
|
|
||||||
id="target-rate"
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
step="0.1"
|
|
||||||
value={turnoverConfig.target_rate}
|
|
||||||
onChange={(e) => setTurnoverConfig(prev => ({
|
|
||||||
...prev,
|
|
||||||
target_rate: parseFloat(e.target.value) || 0
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Button onClick={handleUpdateTurnoverConfig}>
|
|
||||||
Update Turnover Configuration
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</TabsContent>
|
|
||||||
|
|
||||||
<TabsContent value="calculation" className="space-y-4">
|
|
||||||
{/* Sales Velocity Configuration Card */}
|
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>Sales Velocity Windows</CardTitle>
|
|
||||||
<CardDescription>Configure time windows for sales velocity calculations</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="grid grid-cols-3 gap-4">
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="daily-window">Daily Window (days)</Label>
|
|
||||||
<Input
|
|
||||||
id="daily-window"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
value={salesVelocityConfig.daily_window_days}
|
|
||||||
onChange={(e) => setSalesVelocityConfig(prev => ({
|
|
||||||
...prev,
|
|
||||||
daily_window_days: parseInt(e.target.value) || 1
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="weekly-window">Weekly Window (days)</Label>
|
|
||||||
<Input
|
|
||||||
id="weekly-window"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
value={salesVelocityConfig.weekly_window_days}
|
|
||||||
onChange={(e) => setSalesVelocityConfig(prev => ({
|
|
||||||
...prev,
|
|
||||||
weekly_window_days: parseInt(e.target.value) || 1
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="monthly-window">Monthly Window (days)</Label>
|
|
||||||
<Input
|
|
||||||
id="monthly-window"
|
|
||||||
type="number"
|
|
||||||
min="1"
|
|
||||||
value={salesVelocityConfig.monthly_window_days}
|
|
||||||
onChange={(e) => setSalesVelocityConfig(prev => ({
|
|
||||||
...prev,
|
|
||||||
monthly_window_days: parseInt(e.target.value) || 1
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Button onClick={handleUpdateSalesVelocityConfig}>
|
|
||||||
Update Sales Velocity Windows
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</TabsContent>
|
|
||||||
</Tabs>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -142,7 +142,7 @@ export function PerformanceMetrics() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="max-w-[700px] space-y-4">
|
||||||
{/* Lead Time Thresholds Card */}
|
{/* Lead Time Thresholds Card */}
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export function StockManagement() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="max-w-[700px] space-y-4">
|
||||||
{/* Stock Thresholds Card */}
|
{/* Stock Thresholds Card */}
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
|
|||||||
@@ -9,15 +9,18 @@ export function Settings() {
|
|||||||
<div className="container mx-auto py-6">
|
<div className="container mx-auto py-6">
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h1 className="text-3xl font-bold">Settings</h1>
|
<h1 className="text-3xl font-bold">Settings</h1>
|
||||||
<p className="text-muted-foreground">Manage your inventory system settings and configurations</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Tabs defaultValue="data-management" className="space-y-4">
|
<Tabs defaultValue="data-management" className="space-y-4">
|
||||||
<TabsList>
|
<TabsList>
|
||||||
<TabsTrigger value="data-management">Data Management</TabsTrigger>
|
<TabsTrigger value="data-management">Data Management</TabsTrigger>
|
||||||
<TabsTrigger value="stock-management">Stock Management</TabsTrigger>
|
<TabsTrigger value="stock-management">Stock Management</TabsTrigger>
|
||||||
<TabsTrigger value="performance-metrics">Performance Metrics</TabsTrigger>
|
<TabsTrigger value="performance-metrics">
|
||||||
<TabsTrigger value="calculation-settings">Calculation Settings</TabsTrigger>
|
Performance Metrics
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="calculation-settings">
|
||||||
|
Calculation Settings
|
||||||
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
<TabsContent value="data-management">
|
<TabsContent value="data-management">
|
||||||
@@ -38,4 +41,4 @@ export function Settings() {
|
|||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user