mirror of
https://github.com/hanzoai/computer.git
synced 2026-09-30 20:55:46 +00:00
Compile with TypeScript 7
Hanzo CI/CD / cicd (push) Failing after 4m30s
CI/CD / cicd (push) Failing after 4m31s
Hanzo CI/CD / cicd (push) Failing after 4m30s
CI/CD / cicd (push) Failing after 4m31s
typescript 7.0.2 is the native compiler, so this is a pin and not a second toolchain. tsc --noEmit on tsconfig.json: 15 diagnostics before and after, the same pre-existing set on both compilers. TypeScript 7 checks strictly by default, which surfaced 24 real gaps this tsconfig had been hiding. No compiler setting moved to quiet them: the query callbacks in adminAnalytics and adminInvoiceActions now name the row each select projects, request headers are a Record<string, string> rather than a HeadersInit that cannot be indexed, an optional amountPaid is checked before it is read, a quote passes undefined rather than null for its optional columns, and sign-up no longer probes an identities field that IAM never returns. Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
+1
-1
@@ -38,7 +38,7 @@
|
|||||||
"node-mocks-http": "^1.15.1",
|
"node-mocks-http": "^1.15.1",
|
||||||
"postcss": "^8.5.6",
|
"postcss": "^8.5.6",
|
||||||
"tailwindcss": "^4.1.16",
|
"tailwindcss": "^4.1.16",
|
||||||
"typescript": "~5.8.2",
|
"typescript": "7.0.2",
|
||||||
"vite": "^6.2.0"
|
"vite": "^6.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ export const InvoiceDocument: React.FC<{ invoice: InvoiceData }> = ({ invoice })
|
|||||||
<Text style={styles.grandTotalLabel}>Total</Text>
|
<Text style={styles.grandTotalLabel}>Total</Text>
|
||||||
<Text style={styles.grandTotalValue}>{formatCurrency(invoice.total)}</Text>
|
<Text style={styles.grandTotalValue}>{formatCurrency(invoice.total)}</Text>
|
||||||
</View>
|
</View>
|
||||||
{invoice.amountPaid > 0 && (
|
{invoice.amountPaid !== undefined && invoice.amountPaid > 0 && (
|
||||||
<View style={styles.totalRow}>
|
<View style={styles.totalRow}>
|
||||||
<Text style={styles.totalLabel}>Amount Paid</Text>
|
<Text style={styles.totalLabel}>Amount Paid</Text>
|
||||||
<Text style={styles.totalValue}>{formatCurrency(invoice.amountPaid)}</Text>
|
<Text style={styles.totalValue}>{formatCurrency(invoice.amountPaid)}</Text>
|
||||||
|
|||||||
+19
-10
@@ -54,6 +54,15 @@ export interface MetricCard {
|
|||||||
suffix?: string;
|
suffix?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The query client hands back untyped rows, so each callback below names the
|
||||||
|
// columns its own select projects.
|
||||||
|
interface RevenueRow { created_at: string; total: number; gpu_type: string | null }
|
||||||
|
interface GPURow { gpu_type: string | null; total: number }
|
||||||
|
interface TotalRow { total: number }
|
||||||
|
interface StatusRow { created_at: string; status: string }
|
||||||
|
interface DatedRow { id: string; created_at: string }
|
||||||
|
interface QuoteLinkRow { rfq_id: string; created_at: string }
|
||||||
|
|
||||||
// Get revenue data grouped by time period
|
// Get revenue data grouped by time period
|
||||||
export async function getRevenueData(
|
export async function getRevenueData(
|
||||||
startDate: Date,
|
startDate: Date,
|
||||||
@@ -92,7 +101,7 @@ export async function getRevenueData(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Aggregate orders into periods
|
// Aggregate orders into periods
|
||||||
orders?.forEach(order => {
|
orders?.forEach((order: RevenueRow) => {
|
||||||
const orderDate = new Date(order.created_at);
|
const orderDate = new Date(order.created_at);
|
||||||
let key: string;
|
let key: string;
|
||||||
|
|
||||||
@@ -198,7 +207,7 @@ export async function getCustomerGrowth(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Count new customers per day
|
// Count new customers per day
|
||||||
customers?.forEach(customer => {
|
customers?.forEach((customer: DatedRow) => {
|
||||||
const date = format(new Date(customer.created_at), 'yyyy-MM-dd');
|
const date = format(new Date(customer.created_at), 'yyyy-MM-dd');
|
||||||
const growth = dailyGrowth.get(date);
|
const growth = dailyGrowth.get(date);
|
||||||
if (growth) {
|
if (growth) {
|
||||||
@@ -228,7 +237,7 @@ export async function getGPUTypeBreakdown(
|
|||||||
const breakdown = new Map<string, GPUTypeBreakdown>();
|
const breakdown = new Map<string, GPUTypeBreakdown>();
|
||||||
let totalRevenue = 0;
|
let totalRevenue = 0;
|
||||||
|
|
||||||
orders.forEach(order => {
|
orders.forEach((order: GPURow) => {
|
||||||
const type = order.gpu_type || 'Unknown';
|
const type = order.gpu_type || 'Unknown';
|
||||||
const existing = breakdown.get(type) || {
|
const existing = breakdown.get(type) || {
|
||||||
gpuType: type,
|
gpuType: type,
|
||||||
@@ -322,7 +331,7 @@ export async function getQuotePerformance(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Aggregate quotes by day and status
|
// Aggregate quotes by day and status
|
||||||
quotes.forEach(quote => {
|
quotes.forEach((quote: StatusRow) => {
|
||||||
const date = format(new Date(quote.created_at), 'yyyy-MM-dd');
|
const date = format(new Date(quote.created_at), 'yyyy-MM-dd');
|
||||||
const perf = performanceMap.get(date);
|
const perf = performanceMap.get(date);
|
||||||
|
|
||||||
@@ -370,13 +379,13 @@ export async function getAverageDealValue(
|
|||||||
return { overall: 0, byGPUType: new Map() };
|
return { overall: 0, byGPUType: new Map() };
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalRevenue = orders.reduce((sum, order) => sum + order.total, 0);
|
const totalRevenue = orders.reduce((sum: number, order: GPURow) => sum + order.total, 0);
|
||||||
const overall = totalRevenue / orders.length;
|
const overall = totalRevenue / orders.length;
|
||||||
|
|
||||||
const byGPUType = new Map<string, number>();
|
const byGPUType = new Map<string, number>();
|
||||||
const gpuTypeTotals = new Map<string, { total: number; count: number }>();
|
const gpuTypeTotals = new Map<string, { total: number; count: number }>();
|
||||||
|
|
||||||
orders.forEach(order => {
|
orders.forEach((order: GPURow) => {
|
||||||
const type = order.gpu_type || 'Unknown';
|
const type = order.gpu_type || 'Unknown';
|
||||||
const existing = gpuTypeTotals.get(type) || { total: 0, count: 0 };
|
const existing = gpuTypeTotals.get(type) || { total: 0, count: 0 };
|
||||||
existing.total += order.total;
|
existing.total += order.total;
|
||||||
@@ -449,8 +458,8 @@ export async function getKeyMetrics(period: '7d' | '30d' | '90d' | '1y' = '30d')
|
|||||||
.gte('created_at', previousStartDate.toISOString())
|
.gte('created_at', previousStartDate.toISOString())
|
||||||
.lte('created_at', previousEndDate.toISOString());
|
.lte('created_at', previousEndDate.toISOString());
|
||||||
|
|
||||||
const currentRevenue = currentOrders?.reduce((sum, order) => sum + order.total, 0) || 0;
|
const currentRevenue = currentOrders?.reduce((sum: number, order: TotalRow) => sum + order.total, 0) || 0;
|
||||||
const previousRevenue = previousOrders?.reduce((sum, order) => sum + order.total, 0) || 0;
|
const previousRevenue = previousOrders?.reduce((sum: number, order: TotalRow) => sum + order.total, 0) || 0;
|
||||||
const revenueChange = previousRevenue > 0 ? ((currentRevenue - previousRevenue) / previousRevenue) * 100 : 0;
|
const revenueChange = previousRevenue > 0 ? ((currentRevenue - previousRevenue) / previousRevenue) * 100 : 0;
|
||||||
|
|
||||||
const currentOrderCount = currentOrders?.length || 0;
|
const currentOrderCount = currentOrders?.length || 0;
|
||||||
@@ -524,8 +533,8 @@ export async function getResponseTimeMetrics(
|
|||||||
['> 3 days', 0]
|
['> 3 days', 0]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
rfqs.forEach(rfq => {
|
rfqs.forEach((rfq: DatedRow) => {
|
||||||
const quote = quotes.find(q => q.rfq_id === rfq.id);
|
const quote = quotes.find((q: QuoteLinkRow) => q.rfq_id === rfq.id);
|
||||||
if (quote) {
|
if (quote) {
|
||||||
const rfqTime = new Date(rfq.created_at).getTime();
|
const rfqTime = new Date(rfq.created_at).getTime();
|
||||||
const quoteTime = new Date(quote.created_at).getTime();
|
const quoteTime = new Date(quote.created_at).getTime();
|
||||||
|
|||||||
@@ -309,8 +309,8 @@ export const getOrdersWithoutInvoices = async (): Promise<Order[]> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Filter orders that don't have invoices
|
// Filter orders that don't have invoices
|
||||||
const invoicedOrderIds = new Set(invoices.map(inv => inv.order_id));
|
const invoicedOrderIds = new Set(invoices.map((inv: { order_id: string }) => inv.order_id));
|
||||||
return orders.filter(order => !invoicedOrderIds.has(order.id));
|
return orders.filter((order: Order) => !invoicedOrderIds.has(order.id));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching orders without invoices:', error);
|
console.error('Error fetching orders without invoices:', error);
|
||||||
return [];
|
return [];
|
||||||
@@ -335,7 +335,7 @@ export const markInvoiceAsPaid = async (
|
|||||||
.select('amount_due')
|
.select('amount_due')
|
||||||
.eq('id', invoiceId)
|
.eq('id', invoiceId)
|
||||||
.single()
|
.single()
|
||||||
.then(res => res.data?.amount_due || 0),
|
.then((res: { data: { amount_due: number } | null }) => res.data?.amount_due || 0),
|
||||||
amount_due: 0
|
amount_due: 0
|
||||||
})
|
})
|
||||||
.eq('id', invoiceId)
|
.eq('id', invoiceId)
|
||||||
|
|||||||
+2
-2
@@ -24,7 +24,7 @@ const API_BASE_URL = import.meta.env.VITE_API_URL || '/api';
|
|||||||
interface RequestOptions {
|
interface RequestOptions {
|
||||||
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
||||||
body?: any;
|
body?: any;
|
||||||
headers?: HeadersInit;
|
headers?: Record<string, string>;
|
||||||
retries?: number;
|
retries?: number;
|
||||||
retryDelay?: number;
|
retryDelay?: number;
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ export async function apiRequest<T = any>(
|
|||||||
// Get current session for authentication
|
// Get current session for authentication
|
||||||
const { data: { session } } = await supabase.auth.getSession();
|
const { data: { session } } = await supabase.auth.getSession();
|
||||||
|
|
||||||
const requestHeaders: HeadersInit = {
|
const requestHeaders: Record<string, string> = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
...headers,
|
...headers,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -424,8 +424,8 @@ ${revenueData.map(d => `${d.date},${d.revenue},${d.orders}`).join('\n')}`;
|
|||||||
validUntil.setDate(validUntil.getDate() + quoteValidDays);
|
validUntil.setDate(validUntil.getDate() + quoteValidDays);
|
||||||
|
|
||||||
const quoteData = {
|
const quoteData = {
|
||||||
rfq_id: selectedRFQ || null,
|
rfq_id: selectedRFQ || undefined,
|
||||||
cluster_request_id: selectedClusterRequest || null,
|
cluster_request_id: selectedClusterRequest || undefined,
|
||||||
quote_number: generateQuoteNumber(),
|
quote_number: generateQuoteNumber(),
|
||||||
items: quoteItems.filter(item => item.description),
|
items: quoteItems.filter(item => item.description),
|
||||||
subtotal,
|
subtotal,
|
||||||
@@ -433,7 +433,7 @@ ${revenueData.map(d => `${d.date},${d.revenue},${d.orders}`).join('\n')}`;
|
|||||||
total,
|
total,
|
||||||
payment_terms: paymentTerms,
|
payment_terms: paymentTerms,
|
||||||
valid_until: validUntil.toISOString(),
|
valid_until: validUntil.toISOString(),
|
||||||
notes: quoteNotes || null,
|
notes: quoteNotes || undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
await createQuote(quoteData);
|
await createQuote(quoteData);
|
||||||
|
|||||||
@@ -60,12 +60,9 @@ const SignUp: React.FC = () => {
|
|||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
|
|
||||||
if (data.user) {
|
if (data.user) {
|
||||||
// Check if email confirmation is required
|
// IAM owns email confirmation, and signUp redirects there rather than
|
||||||
if (data.user.identities && data.user.identities.length === 0) {
|
// returning a user, so there is nothing to probe here.
|
||||||
setError('Please check your email to confirm your account.');
|
navigate('/dashboard');
|
||||||
} else {
|
|
||||||
navigate('/dashboard');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
setError(err.message || 'An error occurred during sign up');
|
setError(err.message || 'An error occurred during sign up');
|
||||||
|
|||||||
Reference in New Issue
Block a user