EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
page.tsx
Go to the documentation of this file.
1"use client";
2
3import { useState, useEffect } from 'react';
4import { Icon } from '@/contexts/IconContext';
5
6interface LowPricedProduct {
7 id: number;
8 sku: string;
9 name: string;
10 cost: number;
11 sellPrice: number;
12 margin: number;
13 salesInfo: string;
14}
15
16export default function ProductsPricedLowReport() {
17 const [products, setProducts] = useState<LowPricedProduct[]>([]);
18 const [loading, setLoading] = useState(true);
19 const [error, setError] = useState<string | null>(null);
20 const [totalProducts, setTotalProducts] = useState(0);
21
22 useEffect(() => {
23 fetchProducts();
24 }, []);
25
26 const fetchProducts = async () => {
27 try {
28 setLoading(true);
29 setError(null);
30
31 const response = await fetch('/api/v1/elink/advisor/products-priced-low');
32 const data = await response.json();
33
34 if (!response.ok) {
35 throw new Error(data.error || 'Failed to fetch products');
36 }
37
38 setProducts(data.products || []);
39 setTotalProducts(data.totalProducts || 0);
40 } catch (err: any) {
41 console.error('Error fetching products:', err);
42 setError(err.message);
43 } finally {
44 setLoading(false);
45 }
46 };
47
48 if (loading) {
49 return (
50 <div className="p-6 min-h-screen bg-bg">
51 <div className="mb-6">
52 <div className="flex items-center gap-3 mb-2">
53 <a href="/pages/reports?source=advisor" className="text-muted hover:text-brand">
54 <Icon name="arrow_back" size={24} />
55 </a>
56 <h1 className="text-3xl font-bold text-text">Products Priced Below Cost</h1>
57 </div>
58 <p className="text-muted ml-9">
59 Products with selling prices below their cost price
60 </p>
61 </div>
62 <div className="flex items-center justify-center py-12">
63 <div className="text-center">
64 <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-brand mx-auto mb-4"></div>
65 <p className="text-muted">Analyzing product pricing...</p>
66 </div>
67 </div>
68 </div>
69 );
70 }
71
72 if (error) {
73 return (
74 <div className="p-6 min-h-screen bg-bg">
75 <div className="mb-6">
76 <div className="flex items-center gap-3 mb-2">
77 <a href="/pages/reports?source=advisor" className="text-muted hover:text-brand">
78 <Icon name="arrow_back" size={24} />
79 </a>
80 <h1 className="text-3xl font-bold text-text">Products Priced Below Cost</h1>
81 </div>
82 </div>
83 <div className="bg-surface rounded-lg shadow-sm border border-border p-6">
84 <div className="flex items-center gap-3 text-error mb-4">
85 <Icon name="error" size={24} />
86 <span className="font-medium">Error loading products</span>
87 </div>
88 <p className="text-muted mb-4">{error}</p>
89 <button
90 onClick={fetchProducts}
91 className="px-4 py-2 bg-brand text-white rounded hover:bg-brand2"
92 >
93 Retry
94 </button>
95 </div>
96 </div>
97 );
98 }
99
100 return (
101 <div className="p-6 min-h-screen bg-bg">
102 <div className="mb-6">
103 <div className="flex items-center gap-3 mb-2">
104 <a href="/pages/reports?source=advisor" className="text-muted hover:text-brand">
105 <Icon name="arrow_back" size={24} />
106 </a>
107 <h1 className="text-3xl font-bold text-text">Products Priced Below Cost</h1>
108 </div>
109 <p className="text-muted ml-9">
110 Products with selling prices below their cost price
111 </p>
112 {totalProducts > 0 && (
113 <p className="text-muted text-sm ml-9 mt-1">
114 Analyzed {totalProducts} products • Found {products.length} priced below cost
115 </p>
116 )}
117 </div>
118
119 <div className="bg-surface rounded-lg shadow-sm border border-border overflow-hidden">
120 <div className="overflow-x-auto">
121 <table className="w-full">
122 <thead className="bg-[var(--brand)] text-surface">
123 <tr>
124 <th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
125 SKU
126 </th>
127 <th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
128 Product Name
129 </th>
130 <th className="px-6 py-3 text-right text-xs font-medium uppercase tracking-wider">
131 Cost Price
132 </th>
133 <th className="px-6 py-3 text-right text-xs font-medium uppercase tracking-wider">
134 Sell Price
135 </th>
136 <th className="px-6 py-3 text-right text-xs font-medium uppercase tracking-wider">
137 Margin %
138 </th>
139 <th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
140 Sales Info
141 </th>
142 <th className="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider">
143 Actions
144 </th>
145 </tr>
146 </thead>
147 <tbody className="divide-y divide-border">
148 {products.length === 0 ? (
149 <tr>
150 <td colSpan={7} className="px-6 py-12 text-center">
151 <Icon name="check_circle" size={48} className="text-success mx-auto mb-3" />
152 <p className="text-muted">All products are priced correctly</p>
153 <p className="text-muted text-sm mt-2">No products found with sell price below cost</p>
154 </td>
155 </tr>
156 ) : (
157 products.map((product) => (
158 <tr key={product.id} className="hover:bg-surface-2">
159 <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-text">
160 {product.sku || <span className="text-muted italic">No SKU</span>}
161 </td>
162 <td className="px-6 py-4 text-sm text-text">
163 {product.name}
164 </td>
165 <td className="px-6 py-4 whitespace-nowrap text-sm text-right text-muted">
166 ${product.cost.toFixed(2)}
167 </td>
168 <td className="px-6 py-4 whitespace-nowrap text-sm text-right text-error">
169 ${product.sellPrice.toFixed(2)}
170 </td>
171 <td className="px-6 py-4 whitespace-nowrap text-right">
172 <span className={`px-2 py-1 text-xs font-medium rounded ${
173 product.margin < -10 ? 'bg-error/20 text-error' :
174 product.margin < -5 ? 'bg-warning/20 text-warning' :
175 'bg-surface-2 text-muted'
176 }`}>
177 {product.margin.toFixed(1)}%
178 </span>
179 </td>
180 <td className="px-6 py-4 text-sm text-muted">
181 {product.salesInfo || <span className="text-muted italic">-</span>}
182 </td>
183 <td className="px-6 py-4 whitespace-nowrap text-sm space-x-3">
184 <a
185 href={`/pages/products/${product.id}`}
186 className="text-brand hover:text-brand2"
187 >
188 Edit Price
189 </a>
190 <a
191 href={`/pages/products/${product.id}`}
192 className="text-info hover:text-info/80"
193 >
194 View
195 </a>
196 </td>
197 </tr>
198 ))
199 )}
200 </tbody>
201 </table>
202 </div>
203 </div>
204 </div>
205 );
206}