mirror of
https://github.com/christianvidalwolf-prog/Craze-Data-check.git
synced 2026-08-03 14:05:25 +02:00
feat: show EOL not neccessary for OOC products with 0 stock
This commit is contained in:
@@ -0,0 +1,23 @@
|
|||||||
|
// Vercel serverless function — proxies the Dropbox file server-side (no CORS)
|
||||||
|
export default async function handler(req, res) {
|
||||||
|
const fileUrl =
|
||||||
|
'https://dl.dropboxusercontent.com/scl/fi/nkyabkq2jdwfudof2ovrl/Data-Matrix.xlsx' +
|
||||||
|
'?rlkey=1cz5fuabwipqqivihii7sybw0&st=io0g4wvb&dl=1';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const upstream = await fetch(fileUrl, {
|
||||||
|
headers: { 'User-Agent': 'Mozilla/5.0' },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!upstream.ok) {
|
||||||
|
return res.status(upstream.status).send(`Dropbox error: ${upstream.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = await upstream.arrayBuffer();
|
||||||
|
res.setHeader('Content-Type', 'application/octet-stream');
|
||||||
|
res.setHeader('Cache-Control', 'no-store');
|
||||||
|
res.send(Buffer.from(buffer));
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500).send('Proxy error: ' + err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-2
@@ -24,8 +24,11 @@ export default function App() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadDefaultData = async () => {
|
const loadDefaultData = async () => {
|
||||||
// Use Vite's dev proxy to avoid CORS issues
|
// In dev: Vite proxy handles /dropbox-file (see vite.config.ts)
|
||||||
const fileUrl = '/dropbox-file/scl/fi/nkyabkq2jdwfudof2ovrl/Data-Matrix.xlsx?rlkey=1cz5fuabwipqqivihii7sybw0&st=io0g4wvb&dl=1';
|
// In prod: Vercel serverless function at /api/dropbox-proxy handles it
|
||||||
|
const fileUrl = import.meta.env.DEV
|
||||||
|
? '/dropbox-file/scl/fi/nkyabkq2jdwfudof2ovrl/Data-Matrix.xlsx?rlkey=1cz5fuabwipqqivihii7sybw0&st=io0g4wvb&dl=1'
|
||||||
|
: '/api/dropbox-proxy';
|
||||||
|
|
||||||
setIsLoadingDefault(true);
|
setIsLoadingDefault(true);
|
||||||
setDefaultLoadError(null);
|
setDefaultLoadError(null);
|
||||||
|
|||||||
@@ -76,6 +76,14 @@ export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps)
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getRowColor = (row: ExcelRow) => {
|
const getRowColor = (row: ExcelRow) => {
|
||||||
|
// EOL Rule: OOC Classification and 0 stock (Item Available)
|
||||||
|
const classification = String(row[COLUMNS.CLASSIFICATION] || '').toUpperCase();
|
||||||
|
const stock = Number(row[COLUMNS.ITEM_AVAILABLE] || 0);
|
||||||
|
|
||||||
|
if (classification === 'OOC' && stock === 0) {
|
||||||
|
return 'bg-yellow-500/10 hover:bg-yellow-500/20'; // EOL Highlight
|
||||||
|
}
|
||||||
|
|
||||||
const fields = [row[COLUMNS.LONG_DE], row[COLUMNS.LONG_EN], row[COLUMNS.SHORT_DE], row[COLUMNS.SHORT_EN]];
|
const fields = [row[COLUMNS.LONG_DE], row[COLUMNS.LONG_EN], row[COLUMNS.SHORT_DE], row[COLUMNS.SHORT_EN]];
|
||||||
const filled = fields.filter(Boolean).length;
|
const filled = fields.filter(Boolean).length;
|
||||||
if (filled === 4) return 'bg-green-900/10 hover:bg-green-900/20';
|
if (filled === 4) return 'bg-green-900/10 hover:bg-green-900/20';
|
||||||
@@ -83,8 +91,17 @@ export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps)
|
|||||||
return 'bg-yellow-900/10 hover:bg-yellow-900/20';
|
return 'bg-yellow-900/10 hover:bg-yellow-900/20';
|
||||||
};
|
};
|
||||||
|
|
||||||
const Badge = ({ content }: { content: any }) => {
|
const Badge = ({ content, row }: { content: any, row: ExcelRow }) => {
|
||||||
if (content) return <span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-500/20 text-green-400 border border-green-500/30">✓</span>;
|
if (content) return <span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-500/20 text-green-400 border border-green-500/30">✓</span>;
|
||||||
|
|
||||||
|
// EOL Exception
|
||||||
|
const classification = String(row[COLUMNS.CLASSIFICATION] || '').toUpperCase();
|
||||||
|
const stock = Number(row[COLUMNS.ITEM_AVAILABLE] || 0);
|
||||||
|
|
||||||
|
if (classification === 'OOC' && stock === 0) {
|
||||||
|
return <span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-yellow-500/20 text-yellow-400 border border-yellow-500/30">EOL not neccessary</span>;
|
||||||
|
}
|
||||||
|
|
||||||
return <span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-500/20 text-red-400 border border-red-500/30">✗ Missing</span>;
|
return <span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-500/20 text-red-400 border border-red-500/30">✗ Missing</span>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -184,10 +201,10 @@ export function ProductDescriptions({ data, onEdit }: ProductDescriptionsProps)
|
|||||||
<td className="px-4 py-3 font-medium text-white max-w-[300px] truncate" title={row[COLUMNS.ARTICLE_NAME]}>{row[COLUMNS.ARTICLE_NAME]}</td>
|
<td className="px-4 py-3 font-medium text-white max-w-[300px] truncate" title={row[COLUMNS.ARTICLE_NAME]}>{row[COLUMNS.ARTICLE_NAME]}</td>
|
||||||
<td className="px-4 py-3 text-slate-300">{row[COLUMNS.LINE]}</td>
|
<td className="px-4 py-3 text-slate-300">{row[COLUMNS.LINE]}</td>
|
||||||
<td className="px-4 py-3 text-slate-300">{row[COLUMNS.LICENSE]}</td>
|
<td className="px-4 py-3 text-slate-300">{row[COLUMNS.LICENSE]}</td>
|
||||||
<td className="px-4 py-3"><Badge content={row[COLUMNS.LONG_DE]} /></td>
|
<td className="px-4 py-3"><Badge content={row[COLUMNS.LONG_DE]} row={row} /></td>
|
||||||
<td className="px-4 py-3"><Badge content={row[COLUMNS.LONG_EN]} /></td>
|
<td className="px-4 py-3"><Badge content={row[COLUMNS.LONG_EN]} row={row} /></td>
|
||||||
<td className="px-4 py-3"><Badge content={row[COLUMNS.SHORT_DE]} /></td>
|
<td className="px-4 py-3"><Badge content={row[COLUMNS.SHORT_DE]} row={row} /></td>
|
||||||
<td className="px-4 py-3"><Badge content={row[COLUMNS.SHORT_EN]} /></td>
|
<td className="px-4 py-3"><Badge content={row[COLUMNS.SHORT_EN]} row={row} /></td>
|
||||||
<td className="px-4 py-3 text-right">
|
<td className="px-4 py-3 text-right">
|
||||||
<button
|
<button
|
||||||
onClick={() => onEdit(index)}
|
onClick={() => onEdit(index)}
|
||||||
|
|||||||
+3
-1
@@ -22,5 +22,7 @@ export const COLUMNS = {
|
|||||||
LONG_EN: 63,
|
LONG_EN: 63,
|
||||||
SHORT_DE: 64,
|
SHORT_DE: 64,
|
||||||
SHORT_EN: 65,
|
SHORT_EN: 65,
|
||||||
RECOMMENDED_AGE: 67
|
RECOMMENDED_AGE: 67,
|
||||||
|
CLASSIFICATION: 1, // Classification
|
||||||
|
ITEM_AVAILABLE: 14 // Item Available
|
||||||
};
|
};
|
||||||
|
|||||||
+4
-5
@@ -1,8 +1,7 @@
|
|||||||
{
|
{
|
||||||
"rewrites": [
|
"functions": {
|
||||||
{
|
"api/dropbox-proxy.js": {
|
||||||
"source": "/dropbox-file/:path*",
|
"runtime": "nodejs20.x"
|
||||||
"destination": "https://dl.dropboxusercontent.com/:path*"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user