diff --git a/.github/workflows/contract.yml b/.github/workflows/contract.yml index 8b5790e..4bc7446 100644 --- a/.github/workflows/contract.yml +++ b/.github/workflows/contract.yml @@ -20,13 +20,10 @@ jobs: with: targets: wasm32-unknown-unknown - - name: Install cargo-binstall - run: | - curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install.sh | sh - - name: Install cargo-audit and cargo-deny run: | - cargo binstall -y cargo-audit cargo-deny + cargo install cargo-audit --locked + cargo install cargo-deny --locked - name: Run cargo audit run: | diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 62dd98d..d2ceebb 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,5 +1,11 @@ import { useState } from "react"; -import { Link, Route, Routes, useLocation, useNavigate } from "react-router-dom"; +import { + Link, + Route, + Routes, + useLocation, + useNavigate, +} from "react-router-dom"; import { CreateProposalModal } from "./components/CreateProposalModal"; import { useContract } from "./hooks/useContract"; import { useEventPolling } from "./hooks/useEventPolling"; @@ -10,6 +16,7 @@ import { DashboardPage } from "./pages/DashboardPage"; import { HistoryPage } from "./pages/HistoryPage"; import { NotFoundPage } from "./pages/NotFoundPage"; import { OwnersPage } from "./pages/OwnersPage"; +import { ProposalDetailPage } from "./pages/ProposalDetailPage"; import { SettingsPage } from "./pages/SettingsPage"; import type { Proposal } from "./types/accord"; @@ -34,6 +41,8 @@ export default function App() { const navigate = useNavigate(); const location = useLocation(); + const { proposals, owners, ownerAddresses, stats, loading, error, refresh } = + useContract(wallet.address); const { proposals, owners, @@ -49,13 +58,13 @@ export default function App() { useNotifications(wallet.address, proposals); const activeProposals = proposals.filter((proposal) => - ["pending", "ready"].includes(proposal.status) + ["pending", "ready"].includes(proposal.status), ); const isOwner = Boolean( - wallet.address && ownerAddresses.includes(wallet.address) + wallet.address && ownerAddresses.includes(wallet.address), ); const showReadOnlyBanner = Boolean( - wallet.address && !loading && !error && !isOwner + wallet.address && !loading && !error && !isOwner, ); async function withTx( @@ -96,6 +105,8 @@ export default function App() { return withTx(() => approveProposal(wallet.address!, id), { id, patch: { + approvals: newApprovals, + status: newStatus, approvals, status, userHasApproved: true, @@ -134,7 +145,7 @@ export default function App() { const thresholdStat = stats.find((stat) => stat.label === "Threshold"); const threshold = Number.parseInt( thresholdStat?.value.split(" ")[0] ?? "0", - 10 + 10, ); function shortenAddr(addr: string) { @@ -147,6 +158,7 @@ export default function App() {
@@ -163,6 +175,7 @@ export default function App() { + Your wallet network does not match this app. Expected network:{" "} + {import.meta.env.VITE_NETWORK_PASSPHRASE}. Switch Freighter network + to continue.
Your wallet network does not match this app. Expected network:{" "} {import.meta.env.VITE_NETWORK_PASSPHRASE}. Switch Freighter network to @@ -261,7 +278,9 @@ export default function App() { />
-

Freighter wallet required

+

+ Freighter wallet required +

Freighter is the supported browser extension for signing Stellar transactions in Accord. Install it to connect a wallet and use the @@ -276,6 +295,36 @@ export default function App() { Install Freighter

+ ) : loading ? ( +
+ Loading contract data… +
+ ) : page === "dashboard" ? ( + setShowCreate(true)} + error={null} + loading={loading} + /> + ) : page === "history" ? ( + + ) : page === "owners" ? ( + s.label === "Threshold")?.value.split(" ")[0] || + "0", + )} + totalOwners={owners.length} + /> + ) : page === "settings" ? ( + ) : ( } /> + } /> navigate("/app")} />} diff --git a/frontend/src/pages/ProposalDetailPage.tsx b/frontend/src/pages/ProposalDetailPage.tsx index d13de87..028ad93 100644 --- a/frontend/src/pages/ProposalDetailPage.tsx +++ b/frontend/src/pages/ProposalDetailPage.tsx @@ -1,4 +1,109 @@ import { Link, useParams } from "react-router-dom"; +import { useProposal } from "../hooks/useProposal"; + +export function ProposalDetailPage() { + const { id: idParam } = useParams(); + const proposalId = idParam ? Number(idParam) : NaN; + const invalidId = !idParam || Number.isNaN(proposalId); + const { proposal, loading, error } = useProposal(invalidId ? -1 : proposalId); + + return ( +
+
+ + Dashboard + + + + Proposal #{idParam ?? ""} + +
+ + {invalidId ? ( +
+ Invalid proposal id. +
+ ) : loading ? ( +
+ Loading proposal details… +
+ ) : error ? ( +
+ {error} +
+ ) : !proposal ? ( +
+ Proposal not found. +
+ ) : ( +
+
+
+
+

+ Proposal #{proposal.id} +

+

+ Send {proposal.amount} {proposal.token} +

+
+
+ {proposal.status} +
+
+ +
+
+

+ Recipient +

+

{proposal.to}

+
+
+

+ Proposed by +

+

+ {proposal.proposer} +

+
+
+ +
+
+

+ Created +

+

+ {proposal.createdAt} +

+
+
+

+ Approvals +

+

+ {proposal.approvals}/{proposal.threshold} +

+
+
+ + {proposal.description && ( +
+

+ Description +

+

+ {proposal.description} +

+
+ )} +
+
+ )} import { StatusBadge } from "../components/StatusBadge"; import { useProposal } from "../hooks/useProposal";