Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 3 additions & 1 deletion apps/backoffice-tokenization/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
},
"nav": {
"campaigns": "Campaigns",
"roi": "Return on Investment"
"roi": "Return on Investment",
"documentation": "Documentation",
"documentationTooltip": "View documentation"
},
"home": {
"heroTitle": "Entrepreneur Support",
Expand Down
4 changes: 3 additions & 1 deletion apps/backoffice-tokenization/messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
},
"nav": {
"campaigns": "Campañas",
"roi": "Retorno de Inversión"
"roi": "Retorno de Inversión",
"documentation": "Documentación",
"documentationTooltip": "Ver documentación"
},
"home": {
"heroTitle": "Apoyo al emprendedor",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ const logo: AppSidebarLogoConfig = {
href: "/",
};

const footerItems: AppSidebarFooterItem[] = [
{
label: "Documentation",
icon: BookOpen,
href: "https://interactuar.gitbook.io/interactuar-x-trustless/",
tooltip: "View documentation",
},
];

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

const footerItems: AppSidebarFooterItem[] = [
{
label: t("documentation"),
icon: BookOpen,
href: "https://interactuar.gitbook.io/interactuar-x-trustless/",
tooltip: t("documentationTooltip"),
},
];

const navItems: AppSidebarNavItem[] = [
{
label: t("campaigns"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { useCallback, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
Expand Down Expand Up @@ -67,6 +67,7 @@ function createCampaignSchema(t: (key: string) => string) {
// --- LocalStorage persistence ---

interface FlowState {
step: number;
campaign: CreateCampaignFormValues | null;
escrowContractId: string | null;
escrowEngagementId: string | null;
Expand All @@ -78,6 +79,7 @@ interface FlowState {

function emptyFlowState(): FlowState {
return {
step: 1,
campaign: null,
escrowContractId: null,
escrowEngagementId: null,
Expand Down Expand Up @@ -118,7 +120,9 @@ export function useCreateCampaign() {
const queryClient = useQueryClient();
const { walletAddress } = useWalletContext();
const { deployEscrow } = useEscrowsMutations();
const [step, setStep] = useState(1);

const savedFlow = useMemo(() => loadFlowState(), []);
const [step, setStep] = useState(() => savedFlow.step ?? 1);

const deployPhaseLabels = useMemo(() => [
t("deployPhase1"),
Expand All @@ -127,9 +131,11 @@ export function useCreateCampaign() {

const campaignSchema = useMemo(() => createCampaignSchema(t), [t]);

// --- Escrow state (Step 2) ---
const [escrowStatus, setEscrowStatus] = useState<"idle" | "loading" | "success" | "error">("idle");
const [escrowContractId, setEscrowContractId] = useState<string | null>(null);
// --- Escrow state (Step 2) — restored from localStorage ---
const [escrowStatus, setEscrowStatus] = useState<"idle" | "loading" | "success" | "error">(
savedFlow.escrowContractId ? "success" : "idle",
);
const [escrowContractId, setEscrowContractId] = useState<string | null>(savedFlow.escrowContractId);
const [escrowError, setEscrowError] = useState<string | null>(null);

// --- Deploy state (Step 3) ---
Expand All @@ -138,10 +144,10 @@ export function useCreateCampaign() {
);
const [deployFailedAt, setDeployFailedAt] = useState<number | null>(null);

// --- Form ---
// --- Form — default values restored from localStorage ---
const form = useForm<CreateCampaignFormValues>({
resolver: zodResolver(campaignSchema),
defaultValues: {
defaultValues: savedFlow.campaign ?? {
name: "",
description: "",
poolSize: "" as unknown as number,
Expand All @@ -153,6 +159,18 @@ export function useCreateCampaign() {
mode: "onChange",
});

// Persist form values and step to localStorage continuously
useEffect(() => {
const subscription = form.watch((values) => {
saveFlowState({ campaign: values as CreateCampaignFormValues });
});
return () => subscription.unsubscribe();
}, [form]);

useEffect(() => {
saveFlowState({ step });
}, [step]);

// --- Step navigation ---
const nextStep = async () => {
if (step === 1) {
Expand Down
8 changes: 8 additions & 0 deletions apps/backoffice-tokenization/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,11 @@ const SOROBAN_DECIMAL_SCALE = 1e7;
export function fromStroops(stroops: number | string): number {
return Number(stroops) / SOROBAN_DECIMAL_SCALE;
}

export function formatCurrency(amount: number, currency?: string): string {
const formatted = new Intl.NumberFormat("en-US", {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(amount);
return currency ? `${currency} ${formatted}` : formatted;
}