Skip to content

Commit 2bb583d

Browse files
I see this error with the app, reported by NextJS, please fix it. The er
1 parent 21a0e1d commit 2bb583d

File tree

1 file changed

+171
-53
lines changed

1 file changed

+171
-53
lines changed

src/lib/actions/companies.ts

Lines changed: 171 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { db } from '@/lib/db';
66
import { companies, companyMembers, users, companyShares, companyHoldings, assets as assetsSchema, companyMiningRigs, transactions } from '@/lib/db/schema';
77
import { getSession } from '../session';
88
import { revalidatePath } from 'next/cache';
9-
import { eq, and, desc, or, ilike, notInArray, inArray } from 'drizzle-orm';
9+
import { eq, and, desc, or, ilike, notInArray, inArray, sql } from 'drizzle-orm';
1010
import { getRigById } from '@/lib/mining';
1111

1212
const createCompanySchema = z.object({
@@ -136,7 +136,7 @@ export async function getCompaniesForUserDashboard() {
136136
const membershipsByCompanyId = new Map(userMemberships.map(m => [m.companyId, m]));
137137

138138
const managedCompanies: any[] = [];
139-
const investedCompanies: any[] = [];
139+
let investedCompanies: any[] = [];
140140
const otherCompanies: any[] = [];
141141

142142
for (const company of companiesWithMarketData) {
@@ -162,6 +162,9 @@ export async function getCompaniesForUserDashboard() {
162162
}
163163
}
164164

165+
const managedCompanyIds = new Set(managedCompanies.map(c => c.id));
166+
investedCompanies = investedCompanies.filter(c => !managedCompanyIds.has(c.id));
167+
165168
return { managedCompanies, investedCompanies, otherCompanies };
166169
}
167170

@@ -272,7 +275,6 @@ export async function getCompanyById(companyId: number) {
272275

273276
export type CompanyWithDetails = NonNullable<Awaited<ReturnType<typeof getCompanyById>>>;
274277

275-
276278
// Universal function to calculate a company's Net Asset Value (NAV)
277279
async function getCompanyNAV(companyId: number, tx: any) {
278280
const company = await tx.query.companies.findFirst({
@@ -303,6 +305,170 @@ async function getCompanyNAV(companyId: number, tx: any) {
303305
return parseFloat(company.cash) + holdingsValue + miningRigsValue;
304306
}
305307

308+
export async function buyAssetForCompany(companyId: number, ticker: string, quantity: number): Promise<{ success?: string; error?: string }> {
309+
const session = await getSession();
310+
if (!session?.id) return { error: "Non autorisé." };
311+
if (quantity <= 0) return { error: "La quantité doit être positive." };
312+
313+
try {
314+
const result = await db.transaction(async (tx) => {
315+
const member = await tx.query.companyMembers.findFirst({ where: and(eq(companyMembers.companyId, companyId), eq(companyMembers.userId, session.id)) });
316+
if (!member || member.role !== 'ceo') throw new Error("Seul le PDG peut gérer les actifs de l'entreprise.");
317+
318+
const company = await tx.query.companies.findFirst({ where: eq(companies.id, companyId), columns: { cash: true } });
319+
if (!company) throw new Error("Entreprise non trouvée.");
320+
321+
const asset = await tx.query.assets.findFirst({ where: eq(assetsSchema.ticker, ticker) });
322+
if (!asset) throw new Error("Actif à acheter non trouvé.");
323+
324+
const tradeValue = parseFloat(asset.price) * quantity;
325+
if (parseFloat(company.cash) < tradeValue) throw new Error("Trésorerie de l'entreprise insuffisante.");
326+
327+
// Update company cash
328+
await tx.update(companies).set({ cash: sql`${companies.cash} - ${tradeValue}` }).where(eq(companies.id, companyId));
329+
330+
// Add/update holding
331+
const existingHolding = await tx.query.companyHoldings.findFirst({
332+
where: and(eq(companyHoldings.companyId, companyId), eq(companyHoldings.ticker, ticker)),
333+
});
334+
335+
if (existingHolding) {
336+
const existingQuantity = parseFloat(existingHolding.quantity);
337+
const existingAvgCost = parseFloat(existingHolding.avgCost);
338+
const newTotalQuantity = existingQuantity + quantity;
339+
const newAvgCost = ((existingAvgCost * existingQuantity) + tradeValue) / newTotalQuantity;
340+
await tx.update(companyHoldings).set({ quantity: newTotalQuantity.toString(), avgCost: newAvgCost.toString(), updatedAt: new Date() }).where(eq(companyHoldings.id, existingHolding.id));
341+
} else {
342+
await tx.insert(companyHoldings).values({
343+
companyId: companyId,
344+
ticker: asset.ticker,
345+
name: asset.name,
346+
type: asset.type,
347+
quantity: quantity.toString(),
348+
avgCost: asset.price,
349+
});
350+
}
351+
352+
// Recalculate NAV and new share price because asset values can change
353+
const companyData = await tx.query.companies.findFirst({where: eq(companies.id, companyId)});
354+
const nav = await getCompanyNAV(companyId, tx);
355+
const totalShares = parseFloat(companyData!.totalShares);
356+
if (totalShares > 0) {
357+
const newSharePrice = nav / totalShares;
358+
await tx.update(companies).set({ sharePrice: newSharePrice.toString() }).where(eq(companies.id, companyId));
359+
}
360+
361+
return { success: `L'entreprise a acheté ${quantity} de ${ticker}.` };
362+
});
363+
364+
revalidatePath(`/companies/${companyId}`);
365+
return result;
366+
} catch (error: any) {
367+
return { error: error.message || "Une erreur est survenue lors de l'achat de l'actif." };
368+
}
369+
}
370+
371+
export async function sellAssetForCompany(companyId: number, holdingId: number, quantity: number): Promise<{ success?: string; error?: string }> {
372+
const session = await getSession();
373+
if (!session?.id) return { error: "Non autorisé." };
374+
if (quantity <= 0) return { error: "La quantité doit être positive." };
375+
376+
try {
377+
const result = await db.transaction(async (tx) => {
378+
const member = await tx.query.companyMembers.findFirst({ where: and(eq(companyMembers.companyId, companyId), eq(companyMembers.userId, session.id)) });
379+
if (!member || member.role !== 'ceo') throw new Error("Seul le PDG peut gérer les actifs de l'entreprise.");
380+
381+
const holdingToSell = await tx.query.companyHoldings.findFirst({
382+
where: and(eq(companyHoldings.id, holdingId), eq(companyHoldings.companyId, companyId))
383+
});
384+
385+
if (!holdingToSell) throw new Error("Actif détenu non trouvé.");
386+
if (parseFloat(holdingToSell.quantity) < quantity) throw new Error("Quantité d'actifs de l'entreprise insuffisante pour la vente.");
387+
388+
const asset = await tx.query.assets.findFirst({ where: eq(assetsSchema.ticker, holdingToSell.ticker) });
389+
if (!asset) throw new Error("Actif non trouvé sur le marché.");
390+
391+
const tradeValue = parseFloat(asset.price) * quantity;
392+
393+
await tx.update(companies).set({ cash: sql`${companies.cash} + ${tradeValue}` }).where(eq(companies.id, companyId));
394+
395+
const newQuantity = parseFloat(holdingToSell.quantity) - quantity;
396+
if (newQuantity > 1e-9) {
397+
await tx.update(companyHoldings).set({ quantity: newQuantity.toString(), updatedAt: new Date() }).where(eq(companyHoldings.id, holdingId));
398+
} else {
399+
await tx.delete(companyHoldings).where(eq(companyHoldings.id, holdingId));
400+
}
401+
402+
const companyData = await tx.query.companies.findFirst({where: eq(companies.id, companyId)});
403+
const nav = await getCompanyNAV(companyId, tx);
404+
const totalShares = parseFloat(companyData!.totalShares);
405+
if (totalShares > 0) {
406+
const newSharePrice = nav / totalShares;
407+
await tx.update(companies).set({ sharePrice: newSharePrice.toString() }).where(eq(companies.id, companyId));
408+
}
409+
410+
return { success: `L'entreprise a vendu ${quantity} de ${asset.ticker}.` };
411+
});
412+
413+
revalidatePath(`/companies/${companyId}`);
414+
return result;
415+
416+
} catch (error: any) {
417+
return { error: error.message || "Une erreur est survenue lors de la vente de l'actif." };
418+
}
419+
}
420+
421+
export async function buyMiningRigForCompany(companyId: number, rigId: string): Promise<{ success?: string; error?: string }> {
422+
const session = await getSession();
423+
if (!session?.id) return { error: "Non autorisé." };
424+
425+
const rigToBuy = getRigById(rigId);
426+
if (!rigToBuy) return { error: "Matériel de minage non valide." };
427+
428+
try {
429+
const result = await db.transaction(async (tx) => {
430+
const member = await tx.query.companyMembers.findFirst({ where: and(eq(companyMembers.companyId, companyId), eq(companyMembers.userId, session.id)) });
431+
if (!member || member.role !== 'ceo') throw new Error("Seul le PDG peut acheter du matériel pour l'entreprise.");
432+
433+
const company = await tx.query.companies.findFirst({ where: eq(companies.id, companyId), columns: { cash: true } });
434+
if (!company) throw new Error("Entreprise non trouvée.");
435+
436+
const companyCash = parseFloat(company.cash);
437+
if (companyCash < rigToBuy.price) throw new Error("Trésorerie de l'entreprise insuffisante.");
438+
439+
await tx.update(companies).set({ cash: sql`${companies.cash} - ${rigToBuy.price}` }).where(eq(companies.id, companyId));
440+
441+
const existingRig = await tx.query.companyMiningRigs.findFirst({
442+
where: and(eq(companyMiningRigs.companyId, companyId), eq(companyMiningRigs.rigId, rigId)),
443+
});
444+
445+
if (existingRig) {
446+
await tx.update(companyMiningRigs).set({ quantity: existingRig.quantity + 1 }).where(eq(companyMiningRigs.id, existingRig.id));
447+
} else {
448+
await tx.insert(companyMiningRigs).values({ companyId, rigId, quantity: 1 });
449+
}
450+
451+
const companyData = await tx.query.companies.findFirst({where: eq(companies.id, companyId)});
452+
const newNav = await getCompanyNAV(companyId, tx);
453+
const totalShares = parseFloat(companyData!.totalShares);
454+
if (totalShares > 0) {
455+
const newSharePrice = newNav / totalShares;
456+
await tx.update(companies).set({ sharePrice: newSharePrice.toString() }).where(eq(companies.id, companyId));
457+
}
458+
459+
return { success: `L'entreprise a acheté un ${rigToBuy.name}.` };
460+
});
461+
462+
revalidatePath(`/companies/${companyId}`);
463+
return result;
464+
465+
} catch (error: any) {
466+
console.error("Error buying mining rig for company:", error);
467+
return { error: error.message || "Une erreur est survenue lors de l'achat." };
468+
}
469+
}
470+
471+
306472
export async function investInCompany(companyId: number, amount: number): Promise<{ success?: string; error?: string }> {
307473
const session = await getSession();
308474
if (!session?.id) return { error: "Vous devez être connecté pour investir." };
@@ -530,56 +696,6 @@ export async function withdrawFromCompanyTreasury(companyId: number, amount: num
530696
}
531697
}
532698

533-
export async function buyMiningRigForCompany(companyId: number, rigId: string): Promise<{ success?: string; error?: string }> {
534-
const session = await getSession();
535-
if (!session?.id) return { error: "Non autorisé." };
536-
537-
const rigToBuy = getRigById(rigId);
538-
if (!rigToBuy) return { error: "Matériel de minage non valide." };
539-
540-
try {
541-
const result = await db.transaction(async (tx) => {
542-
const member = await tx.query.companyMembers.findFirst({ where: and(eq(companyMembers.companyId, companyId), eq(companyMembers.userId, session.id)) });
543-
if (!member || member.role !== 'ceo') throw new Error("Seul le PDG peut acheter du matériel pour l'entreprise.");
544-
545-
const company = await tx.query.companies.findFirst({ where: eq(companies.id, companyId), columns: { cash: true } });
546-
if (!company) throw new Error("Entreprise non trouvée.");
547-
548-
const companyCash = parseFloat(company.cash);
549-
if (companyCash < rigToBuy.price) throw new Error("Trésorerie de l'entreprise insuffisante.");
550-
551-
await tx.update(companies).set({ cash: sql`${companies.cash} - ${rigToBuy.price}` }).where(eq(companies.id, companyId));
552-
553-
const existingRig = await tx.query.companyMiningRigs.findFirst({
554-
where: and(eq(companyMiningRigs.companyId, companyId), eq(companyMiningRigs.rigId, rigId)),
555-
});
556-
557-
if (existingRig) {
558-
await tx.update(companyMiningRigs).set({ quantity: existingRig.quantity + 1 }).where(eq(companyMiningRigs.id, existingRig.id));
559-
} else {
560-
await tx.insert(companyMiningRigs).values({ companyId, rigId, quantity: 1 });
561-
}
562-
563-
const fullCompany = await tx.query.companies.findFirst({where: eq(companies.id, companyId)});
564-
const newNav = await getCompanyNAV(companyId, tx);
565-
const totalShares = parseFloat(fullCompany!.totalShares);
566-
if (totalShares > 0) {
567-
const newSharePrice = newNav / totalShares;
568-
await tx.update(companies).set({ sharePrice: newSharePrice.toString() }).where(eq(companies.id, companyId));
569-
}
570-
571-
return { success: `L'entreprise a acheté un ${rigToBuy.name}.` };
572-
});
573-
574-
revalidatePath(`/companies/${companyId}`);
575-
return result;
576-
577-
} catch (error: any) {
578-
console.error("Error buying mining rig for company:", error);
579-
return { error: error.message || "Une erreur est survenue lors de l'achat." };
580-
}
581-
}
582-
583699
export async function searchUsersForCompany(companyId: number, query: string): Promise<{id: number, displayName: string, email: string}[]> {
584700
if (!query || query.length < 2) return [];
585701

@@ -754,3 +870,5 @@ export async function claimCompanyBtc(companyId: number): Promise<{ success?: st
754870
return { error: error.message || "Une erreur est survenue lors de la réclamation des récompenses." };
755871
}
756872
}
873+
874+

0 commit comments

Comments
 (0)