Skip to content

Commit

Permalink
added some DataManager
Browse files Browse the repository at this point in the history
  • Loading branch information
admineral committed Sep 22, 2024
1 parent 4f3d300 commit e8a2ca8
Show file tree
Hide file tree
Showing 11 changed files with 738 additions and 6 deletions.
34 changes: 34 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"cmdk": "^1.0.0",
"csv-parse": "^5.5.6",
"csvtojson": "^2.0.10",
"geist": "^1.3.1",
"next": "^14.2.5",
Expand All @@ -51,6 +52,7 @@
"react-dom": "^18.3.1",
"react-dropzone": "^14.2.3",
"react-icons": "^5.3.0",
"react-intersection-observer": "^9.13.1",
"react-markdown": "^9.0.1",
"recharts": "^2.12.7",
"sonner": "^1.5.0",
Expand All @@ -62,6 +64,7 @@
},
"devDependencies": {
"@ianvs/prettier-plugin-sort-imports": "^4.3.1",
"@types/csv-parse": "^1.1.12",
"@types/eslint": "^8.56.10",
"@types/node": "^20.14.12",
"@types/papaparse": "^5.3.14",
Expand Down
121 changes: 121 additions & 0 deletions src/app/Data2/CSVPreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
'use client';

import React, { useState, useEffect, useCallback } from 'react';
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Button } from "@/components/ui/button";
import { FaSync } from "react-icons/fa";

interface CSVPreviewProps {
fileName: string;
}

interface CombinedRecord {
Client: string;
Warehouse: string;
Product: string;
[key: string]: string | number | { price: number; sales: number };
}

const CSVPreview: React.FC<CSVPreviewProps> = ({ fileName }) => {
const [previewData, setPreviewData] = useState<CombinedRecord[]>([]);
const [headers, setHeaders] = useState<string[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);

const fetchCSVPreview = useCallback(async () => {
console.log(`Fetching preview for ${fileName}`);
setLoading(true);
setError(null);
try {
const response = await fetch(`${window.location.origin}/api/csv-preview?files=Price.csv,Sales.csv`);
console.log(`Response status for ${fileName}:`, response.status);
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Failed to fetch CSV preview: ${response.status}. ${errorText}`);
}
const data = await response.json();
console.log(`Received data for ${fileName}:`, data);
if (data.error) {
throw new Error(data.error);
}
setPreviewData(data.preview || []);
setHeaders(data.headers || []);
} catch (error) {
console.error(`Error fetching CSV preview for ${fileName}:`, error);
setError(error instanceof Error ? error.message : 'An unknown error occurred');
} finally {
setLoading(false);
}
}, [fileName]);

useEffect(() => {
fetchCSVPreview();
}, [fetchCSVPreview]);

const formatValue = (value: string | number | { price: number; sales: number }): string => {
if (typeof value === 'object' && value !== null && 'price' in value && 'sales' in value) {
return `P: ${value.price.toFixed(2)} / S: ${value.sales}`;
}
if (typeof value === 'number') {
return isNaN(value) ? 'N/A' : value.toFixed(2);
}
return String(value);
};

return (
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle>{fileName} Preview</CardTitle>
<Button
variant="outline"
size="sm"
onClick={fetchCSVPreview}
disabled={loading}
>
<FaSync className={`mr-2 h-4 w-4 ${loading ? "animate-spin" : ""}`} />
Refresh
</Button>
</CardHeader>
<CardContent>
{loading && (
<div className="flex justify-center items-center h-32">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
</div>
)}
{error && (
<div className="text-red-500">{error}</div>
)}
{!loading && !error && previewData.length === 0 && (
<div>No data available for {fileName}</div>
)}
{!loading && !error && previewData.length > 0 && (
<div className="overflow-x-auto">
<Table>
<TableHeader>
<TableRow>
{headers.map((header, index) => (
<TableHead key={index}>{header}</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{previewData.map((row, rowIndex) => (
<TableRow key={rowIndex}>
{headers.map((header, cellIndex) => (
<TableCell key={cellIndex}>
{formatValue(row[header])}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</div>
)}
</CardContent>
</Card>
);
};

export default CSVPreview;
142 changes: 142 additions & 0 deletions src/app/Data2/CombinedView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
'use client';

import React, { useState, useEffect, useCallback } from 'react';
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { FaSync } from "react-icons/fa";

interface CombinedRecord {
Client: string;
Warehouse: string;
Product: string;
[key: string]: string | number | { price: number; sales: number };
}

const CombinedView: React.FC = () => {
const [combinedData, setCombinedData] = useState<CombinedRecord[]>([]);
const [headers, setHeaders] = useState<string[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);
const [warehouse, setWarehouse] = useState<string>('');
const [client, setClient] = useState<string>('');
const [product, setProduct] = useState<string>('');

const fetchCombinedData = useCallback(async () => {
console.log('Fetching combined data');
setLoading(true);
setError(null);
try {
const queryParams = new URLSearchParams({
files: 'Price.csv,Sales.csv',
...(warehouse && { warehouse }),
...(client && { client }),
...(product && { product }),
});

const response = await fetch(`/api/csv-preview?${queryParams}`);
if (!response.ok) {
throw new Error('Failed to fetch combined data');
}
const data = await response.json();

if (data.error) {
throw new Error(data.error);
}

setCombinedData(data.preview);
setHeaders(data.headers);
} catch (error) {
console.error('Error fetching combined data:', error);
setError(error instanceof Error ? error.message : 'An unknown error occurred');
} finally {
setLoading(false);
}
}, [warehouse, client, product]);

useEffect(() => {
fetchCombinedData();
}, [fetchCombinedData]);

const formatValue = (value: string | number | { price: number; sales: number }): string => {
if (typeof value === 'object' && value !== null && 'price' in value && 'sales' in value) {
return `P: ${value.price.toFixed(2)} / S: ${value.sales}`;
}
if (typeof value === 'number') {
return isNaN(value) ? 'N/A' : value.toFixed(2);
}
return String(value);
};

return (
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle>Combined Price and Sales View</CardTitle>
<Button
variant="outline"
size="sm"
onClick={fetchCombinedData}
disabled={loading}
>
<FaSync className={`mr-2 h-4 w-4 ${loading ? "animate-spin" : ""}`} />
Refresh
</Button>
</CardHeader>
<CardContent>
<div className="grid grid-cols-3 gap-4 mb-4">
<Input
placeholder="Filter by Warehouse"
value={warehouse}
onChange={(e) => setWarehouse(e.target.value)}
/>
<Input
placeholder="Filter by Client"
value={client}
onChange={(e) => setClient(e.target.value)}
/>
<Input
placeholder="Filter by Product"
value={product}
onChange={(e) => setProduct(e.target.value)}
/>
</div>
{loading && (
<div className="flex justify-center items-center h-32">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
</div>
)}
{error && <div className="text-red-500">{error}</div>}
{!loading && !error && combinedData.length === 0 && (
<div>No data available</div>
)}
{!loading && !error && combinedData.length > 0 && (
<div className="overflow-x-auto">
<Table>
<TableHeader>
<TableRow>
{headers.map((header, index) => (
<TableHead key={index}>{header}</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{combinedData.map((row, rowIndex) => (
<TableRow key={rowIndex}>
{headers.map((header, cellIndex) => (
<TableCell key={cellIndex}>
{formatValue(row[header])}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</div>
)}
</CardContent>
</Card>
);
};

export default CombinedView;
Loading

0 comments on commit e8a2ca8

Please sign in to comment.