130 lines
4.6 KiB
TypeScript
130 lines
4.6 KiB
TypeScript
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 { toast } from "sonner";
|
|
import config from '../../config';
|
|
|
|
interface SalesVelocityConfig {
|
|
id: number;
|
|
cat_id: number | null;
|
|
vendor: string | null;
|
|
daily_window_days: number;
|
|
weekly_window_days: number;
|
|
monthly_window_days: number;
|
|
}
|
|
|
|
export function CalculationSettings() {
|
|
const [salesVelocityConfig, setSalesVelocityConfig] = useState<SalesVelocityConfig>({
|
|
id: 1,
|
|
cat_id: null,
|
|
vendor: null,
|
|
daily_window_days: 30,
|
|
weekly_window_days: 7,
|
|
monthly_window_days: 90
|
|
});
|
|
|
|
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();
|
|
setSalesVelocityConfig(data.salesVelocityConfig);
|
|
} catch (error) {
|
|
toast.error(`Failed to load configuration: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
}
|
|
};
|
|
loadConfig();
|
|
}, []);
|
|
|
|
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'}`);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="max-w-[700px] 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"
|
|
className="[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
|
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"
|
|
className="[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
|
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"
|
|
className="[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
|
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>
|
|
</div>
|
|
);
|
|
}
|