Layout tweaksÏ

This commit is contained in:
2025-01-12 16:11:55 -05:00
parent a6781205a3
commit 4d3f956a03
5 changed files with 10 additions and 637 deletions

View File

@@ -66,7 +66,7 @@ export function CalculationSettings() {
};
return (
<div className="space-y-4">
<div className="max-w-[700px] space-y-4">
{/* Sales Velocity Configuration Card */}
<Card>
<CardHeader>

View File

@@ -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>
);
}

View File

@@ -142,7 +142,7 @@ export function PerformanceMetrics() {
};
return (
<div className="space-y-4">
<div className="max-w-[700px] space-y-4">
{/* Lead Time Thresholds Card */}
<Card>
<CardHeader>

View File

@@ -109,7 +109,7 @@ export function StockManagement() {
};
return (
<div className="space-y-4">
<div className="max-w-[700px] space-y-4">
{/* Stock Thresholds Card */}
<Card>
<CardHeader>

View File

@@ -9,15 +9,18 @@ export function Settings() {
<div className="container mx-auto py-6">
<div className="mb-6">
<h1 className="text-3xl font-bold">Settings</h1>
<p className="text-muted-foreground">Manage your inventory system settings and configurations</p>
</div>
<Tabs defaultValue="data-management" className="space-y-4">
<TabsList>
<TabsTrigger value="data-management">Data Management</TabsTrigger>
<TabsTrigger value="stock-management">Stock Management</TabsTrigger>
<TabsTrigger value="performance-metrics">Performance Metrics</TabsTrigger>
<TabsTrigger value="calculation-settings">Calculation Settings</TabsTrigger>
<TabsTrigger value="performance-metrics">
Performance Metrics
</TabsTrigger>
<TabsTrigger value="calculation-settings">
Calculation Settings
</TabsTrigger>
</TabsList>
<TabsContent value="data-management">
@@ -38,4 +41,4 @@ export function Settings() {
</Tabs>
</div>
);
}
}