Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3355f8b
refact: remo useless files
JoelVR17 Mar 15, 2026
ea9f5e4
feat: add pathname prop to AppSidebar for active state management
JoelVR17 Mar 15, 2026
a01727b
feat: update environment variables and refactor Soroban client integr…
JoelVR17 Mar 17, 2026
f22325f
remove: useless files
JoelVR17 Mar 17, 2026
eec4b44
refact: update imports to use shared utilities and remove unused files
JoelVR17 Mar 17, 2026
950d5dc
refact: update formatCurrency imports and remove StatItem component
JoelVR17 Mar 17, 2026
d49a6f9
remove: useless files
JoelVR17 Mar 17, 2026
e774de0
refact: consolidate numeric input handling and adjust price utilities…
JoelVR17 Mar 17, 2026
c3c9c3b
chore: update .env.example to include default values for API keys
JoelVR17 Mar 17, 2026
1078f50
feat: update environment variables and refactor Soroban service integ…
JoelVR17 Mar 17, 2026
70c2ab3
chore: update .env.example with default values for environment variab…
JoelVR17 Mar 17, 2026
1444a1f
fix: build errors
JoelVR17 Mar 17, 2026
c887b8f
fix: enhance formatCurrency to handle string inputs and ensure safe n…
JoelVR17 Mar 17, 2026
2974217
refact: convert CampaignLoansPage to use client components and intern…
JoelVR17 Mar 17, 2026
336dc81
docs: update docs
JoelVR17 Mar 17, 2026
2efd3d0
feat: introduce ESCROW_EXPLORER_URL constant and update references in…
JoelVR17 Mar 17, 2026
36e39a0
feat: add "View Vault" functionality and update translations for impr…
JoelVR17 Mar 17, 2026
6e02e28
feat: integrate SharedCampaignsView in campaigns and my-investments p…
JoelVR17 Mar 17, 2026
40e9d01
feat: add repayment and claimable filters to campaign filter componen…
JoelVR17 Mar 17, 2026
6663516
fix: correct parameter name in buildContractCallTransaction for ROI p…
JoelVR17 Mar 18, 2026
4dd8332
refact: translations and remove files
JoelVR17 Mar 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,5 @@ Four Soroban contracts sharing `soroban-sdk 23.1.1`. Build with `cargo build --r
## Environment Variables

Each app has a `.env.example`. Key vars:
- **Frontend apps**: `NEXT_PUBLIC_API_KEY`, `NEXT_PUBLIC_API_URL`, `SOURCE_SECRET`
- **Core**: `DATABASE_URL`, `PORT`, `SOURCE_SECRET`, `SOROBAN_RPC_URL`, `*_WASM_HASH` (contract hashes)
- **Frontend apps**: `NEXT_PUBLIC_API_KEY`, `NEXT_PUBLIC_API_URL`, `SOURCE_SECRET`, `NEXT_PUBLIC_SOROBAN_RPC_URL`, `NEXT_PUBLIC_DEFAULT_USDC_ADDRESS`
- **Core**: `DATABASE_URL`, `PORT`, `SOURCE_SECRET`, `SOROBAN_RPC_URL`, `USDC_CONTRACT_ID`, `*_WASM_HASH` (contract hashes)
18 changes: 9 additions & 9 deletions apps/backoffice-tokenization/.env.example
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Trustless Work API Configuration
NEXT_PUBLIC_API_KEY=
# Trustless Work API
NEXT_PUBLIC_API_KEY=""

# Server-side only (for contract deployment)
SOURCE_SECRET=
# Core API (NestJS backend)
NEXT_PUBLIC_CORE_API_URL="http://localhost:4000"
NEXT_PUBLIC_BACKOFFICE_API_KEY=""

# Core API URL (NestJS backend)
NEXT_PUBLIC_CORE_API_URL=http://localhost:4000

# Core API Authentication
NEXT_PUBLIC_BACKOFFICE_API_KEY=
# Soroban / Stellar network
NEXT_PUBLIC_SOROBAN_RPC_URL="https://soroban-testnet.stellar.org"
NEXT_PUBLIC_STELLAR_NETWORK_PASSPHRASE="Test SDF Network ; September 2015"
NEXT_PUBLIC_DEFAULT_USDC_ADDRESS="CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA"
23 changes: 23 additions & 0 deletions apps/backoffice-tokenization/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@
"filterAll": "All",
"filterFundraising": "Fundraising",
"filterActive": "Active",
"filterRepayment": "Repayment",
"filterClaimable": "Claimable",
"filterClosed": "Closed",
"searchPlaceholder": "Search campaigns...",
"status": {
Expand Down Expand Up @@ -157,6 +159,7 @@
"statusHeader": "Status",
"actions": "Actions",
"manageLoans": "Manage Loans",
"viewVault": "View Vault",
"uploadFunds": "Upload Funds",
"updateRoi": "Update ROI",
"loadMore": "Load More",
Expand Down Expand Up @@ -189,6 +192,19 @@
"disable": "Disable",
"enabled": "Vault enabled",
"disabled": "Vault disabled"
},
"updateRoiDialog": {
"title": "Update ROI Percentage — {campaignName}",
"description": "Set a new ROI percentage for this campaign's vault. Value must be between 0 and 100.",
"fieldLabel": "ROI Percentage (%)",
"placeholder": "e.g. 12",
"updatingLabel": "Updating ROI...",
"submitLabel": "Update ROI Percentage",
"successToast": "ROI percentage updated successfully"
},
"errors": {
"walletNotConnected": "Wallet not connected",
"unexpectedError": "Unexpected error"
}
},
"tokens": {
Expand Down Expand Up @@ -238,6 +254,13 @@
"vaultContractAddress": "Vault Contract Address",
"copied": "Copied!",
"copy": "Copy",
"enableVaultSuccessToast": "Vault enabled successfully",
"errors": {
"failedBuildEnableTx": "Failed to build enable transaction.",
"transactionSubmissionFailed": "Transaction submission failed.",
"enableVaultRequestFailed": "Enable vault request did not succeed",
"unexpectedError": "Unexpected error"
},
"validation": {
"priceRequired": "Price is required",
"maxPrice": "Cannot exceed 100%",
Expand Down
23 changes: 23 additions & 0 deletions apps/backoffice-tokenization/messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@
"filterAll": "Todas",
"filterFundraising": "Recaudando",
"filterActive": "Activa",
"filterRepayment": "En Pago",
"filterClaimable": "Reclamable",
"filterClosed": "Cerrada",
"searchPlaceholder": "Buscar campañas...",
"status": {
Expand Down Expand Up @@ -157,6 +159,7 @@
"statusHeader": "Estado",
"actions": "Acciones",
"manageLoans": "Gestionar Préstamos",
"viewVault": "Ver vault",
"uploadFunds": "Subir Fondos",
"updateRoi": "Actualizar ROI",
"loadMore": "Cargar Más",
Expand Down Expand Up @@ -189,6 +192,19 @@
"disable": "Deshabilitar",
"enabled": "Vault habilitado",
"disabled": "Vault deshabilitado"
},
"updateRoiDialog": {
"title": "Actualizar porcentaje de ROI — {campaignName}",
"description": "Establezca un nuevo porcentaje de ROI para el vault de esta campaña. El valor debe estar entre 0 y 100.",
"fieldLabel": "Porcentaje de ROI (%)",
"placeholder": "ej. 12",
"updatingLabel": "Actualizando ROI...",
"submitLabel": "Actualizar porcentaje de ROI",
"successToast": "El porcentaje de ROI se actualizó correctamente"
},
"errors": {
"walletNotConnected": "Wallet no conectada",
"unexpectedError": "Error inesperado"
}
},
"tokens": {
Expand Down Expand Up @@ -238,6 +254,13 @@
"vaultContractAddress": "Dirección del Contrato Vault",
"copied": "¡Copiado!",
"copy": "Copiar",
"enableVaultSuccessToast": "Vault habilitado exitosamente",
"errors": {
"failedBuildEnableTx": "No se pudo construir la transacción para habilitar el vault.",
"transactionSubmissionFailed": "Falló el envío de la transacción.",
"enableVaultRequestFailed": "La solicitud para habilitar el vault no fue exitosa",
"unexpectedError": "Error inesperado"
},
"validation": {
"priceRequired": "El precio es requerido",
"maxPrice": "No puede exceder 100%",
Expand Down
7 changes: 6 additions & 1 deletion apps/backoffice-tokenization/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts");

const nextConfig: NextConfig = {
reactCompiler: true,
transpilePackages: ["@tokenization/shared", "@tokenization/ui", "@tokenization/tw-blocks-shared"],
transpilePackages: [
"@tokenization/shared",
"@tokenization/ui",
"@tokenization/features",
"@tokenization/tw-blocks-shared",
],
turbopack: {
root: "../../",
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import { SectionTitle } from "@/components/shared/section-title";
"use client";

import { SectionTitle } from "@tokenization/ui/section-title";
import { ManageLoansView } from "@/features/campaigns/components/loans/manage-loans-view";
import { useTranslations } from "next-intl";
import { use } from "react";

interface Props {
params: Promise<{ id: string }>;
}

export default async function CampaignLoansPage({ params }: Props) {
const { id } = await params;
export default function CampaignLoansPage({ params }: Props) {
const { id } = use(params);
const t = useTranslations("loans");

return (
<div className="flex flex-col gap-6">
<SectionTitle
title="Manejar Préstamos"
description="Administra los hitos y préstamos de la campaña."
title={t("title")}
description={t("description")}
/>
<ManageLoansView contractId={id} />
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { SectionTitle } from "@/components/shared/section-title";
import { SectionTitle } from "@tokenization/ui/section-title";
import { CreateCampaignStepper } from "@/features/campaigns/components/create/create-campaign-stepper";
import { useTranslations } from "next-intl";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,77 @@
"use client";

import { Link } from "@/i18n/navigation";
import { SectionTitle } from "@/components/shared/section-title";
import { CampaignsView } from "@/features/campaigns/components/campaigns-view";
import { SharedCampaignsView } from "@tokenization/features/campaign";
import { Button } from "@tokenization/ui/button";
import { Plus } from "lucide-react";
import { useTranslations } from "next-intl";
import type { SharedCampaign } from "@tokenization/shared/src/types/campaign";
import { useCampaigns } from "@/features/campaigns/hooks/use-campaigns";
import { CampaignList } from "@/features/campaigns/components/campaign-list";
import type { Campaign } from "@/features/campaigns/types/campaign.types";

function backofficeToShared(c: Campaign): SharedCampaign {
return {
id: c.id,
title: c.name,
description: c.description ?? "",
status: c.status,
loansCompleted: 0,
investedAmount: 0,
currency: "USDC",
vaultId: c.vaultId ?? null,
escrowId: c.escrowId,
poolSize: c.poolSize,
};
}

export default function CampaignsPage() {
const t = useTranslations("campaigns");

return (
<div className="flex flex-col gap-6">
<div className="flex flex-wrap justify-between gap-1">
<SectionTitle
title={t("title")}
description={t("description")}
/>
<div className="flex gap-2">
const { data: rawCampaigns = [], isLoading, isError } = useCampaigns();
const campaigns: SharedCampaign[] = rawCampaigns.map(backofficeToShared);

<Button size="lg" asChild>
<Link href="/campaigns/new">
<Plus size={16} />
{t("newCampaign")}
</Link>
</Button>
</div>
const toolbarLabels = {
searchPlaceholder: t("searchPlaceholder"),
filterAll: t("filterAll"),
filterFundraising: t("filterFundraising"),
filterActive: t("filterActive"),
filterRepayment: t("filterRepayment"),
filterClaimable: t("filterClaimable"),
filterClosed: t("filterClosed"),
};

if (isError) {
return (
<div className="flex items-center justify-center py-16 text-destructive text-sm">
{t("loadError")}
</div>
<CampaignsView />
</div>
);
}

return (
<SharedCampaignsView
title={t("title")}
description={t("description")}
campaigns={campaigns}
isLoading={isLoading}
loadingMessage={t("loading")}
emptyMessage={t("empty")}
headerActions={
<Button size="lg" asChild>
<Link href="/campaigns/new">
<Plus size={16} />
{t("newCampaign")}
</Link>
</Button>
}
toolbarLabels={toolbarLabels}
>
{(filteredCampaigns: SharedCampaign[]) => {
const ids = new Set(filteredCampaigns.map((c) => c.id));
const rawFiltered = rawCampaigns.filter((r) => ids.has(r.id));
return <CampaignList campaigns={rawFiltered} />;
}}
</SharedCampaignsView>
);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { SectionTitle } from "@/components/shared/section-title";
import { SectionTitle } from "@tokenization/ui/section-title";
import { RoiView } from "@/features/campaigns/components/roi/roi-view";
import { useTranslations } from "next-intl";

Expand Down
2 changes: 1 addition & 1 deletion apps/backoffice-tokenization/src/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Toaster } from "@tokenization/ui/sonner";
import { WalletProvider } from "@tokenization/tw-blocks-shared/src/wallet-kit/WalletProvider";
import type { ReactNode } from "react";
import { Inter } from "next/font/google";
import { cn } from "@/lib/utils";
import { cn } from "@tokenization/shared/lib/utils";
import { NextIntlClientProvider } from "next-intl";
import { SharedTranslationProvider } from "@tokenization/tw-blocks-shared/src/i18n/TranslationProvider";
import sharedEn from "@tokenization/tw-blocks-shared/src/i18n/messages/en.json";
Expand Down
2 changes: 0 additions & 2 deletions apps/backoffice-tokenization/src/app/[locale]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { HomeView } from "@/features/home/HomeView";
import { Header } from "@/components/shared/Header";

export default function Home() {
return (
<div className="min-h-screen w-full bg-[#def1f8]">
<div className="container relative z-10 mx-auto">
<Header />
<HomeView />
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
"use client";

import { SidebarTrigger } from "@tokenization/ui/sidebar";
import { LanguageSwitcher } from "@/components/shared/language-switcher";
import { LanguageSwitcher } from "@tokenization/ui/language-switcher";
import { usePathname, useRouter } from "@/i18n/navigation";

export function AppHeader() {
const router = useRouter();
const pathname = usePathname();

return (
<header className="flex h-14 shrink-0 items-center justify-between border-b border-border bg-card px-4">
<SidebarTrigger className="md:hidden" />
<div className="ml-auto">
<LanguageSwitcher />
<LanguageSwitcher
pathname={pathname}
onSwitchLocale={(locale) => router.replace(pathname, { locale })}
/>
</div>
</header>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from "@tokenization/ui/app-sidebar";
import { SidebarWalletButton } from "@tokenization/ui/sidebar-wallet-button";
import { useTranslations } from "next-intl";
import { usePathname } from "@/i18n/navigation";

const logo: AppSidebarLogoConfig = {
element: (
Expand All @@ -27,6 +28,7 @@ const logo: AppSidebarLogoConfig = {

export function AppSidebar() {
const t = useTranslations("nav");
const pathname = usePathname();

const footerItems: AppSidebarFooterItem[] = [
{
Expand All @@ -52,6 +54,7 @@ export function AppSidebar() {

return (
<SharedAppSidebar
pathname={pathname}
navItems={navItems}
logo={logo}
footerItems={footerItems}
Expand Down
12 changes: 0 additions & 12 deletions apps/backoffice-tokenization/src/components/shared/Header.tsx

This file was deleted.

Loading