Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1e962c5
refactor(activity): remove network toggle and separate event title
jlm0 Dec 6, 2025
0760dbf
chore: add CLAUDE.md to .gitignore
jlm0 Dec 6, 2025
cbd41e0
fix: USD-based project issuance display and token calculation
jlm0 Dec 6, 2025
ef909f1
feat: add Safe support for ERC-20 token deployment
jlm0 Dec 6, 2025
81028a0
chore: bump para version to 2.0.0
jlm0 Dec 6, 2025
c1b6f66
fix: show loading state instead of empty state while project loads
jlm0 Dec 6, 2025
13c5771
fix: prevent undefined seoProps serialization in getStaticProps
jlm0 Dec 6, 2025
4b756a1
feat: show NFT quick actions for Safe signers
jlm0 Dec 6, 2025
59572a6
fix: filter out burnEvent from activity feeds
jlm0 Dec 6, 2025
81ff499
feat: link $NANA fee to Bananapus project in activity feed
jlm0 Dec 6, 2025
823c404
fix: rename token badge from 'Juicebox native' to 'Token credits'
jlm0 Dec 6, 2025
e1fac6d
feat: show 'None' in tokens section when no tokens exist
jlm0 Dec 6, 2025
57718bf
fix: disable animations on analytics charts
jlm0 Dec 6, 2025
9c98529
fix: improve omnichain gas estimation with dynamic per-chain estimates
jlm0 Dec 7, 2025
feb4da3
fix: handle V4/V5 bigint price comparison in NFT tier sorting
jlm0 Dec 7, 2025
5b0b65c
fix: display balance for project's chain in pay card
jlm0 Dec 7, 2025
1267ce9
fix: pass chainId to cash out quote calculation hooks
jlm0 Dec 7, 2025
e547daa
fix: update cash out modal to show pendulum loading animation
jlm0 Dec 7, 2025
e72c3bc
fix: change unlocked rulesets badge text to beginner friendly
jlm0 Dec 7, 2025
4d2b7f0
fix: add new localization strings for project features and confirmations
jlm0 Dec 7, 2025
8e3ffdb
fix: resolve upcoming ruleset loading states for start time, payer is…
jlm0 Dec 7, 2025
c9e0d2e
feat: add ruleset history navigation with cycle selector
jlm0 Dec 8, 2025
a751d0b
Update messages.pot
jlm0 Dec 8, 2025
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,5 @@ src/generated

.vercel
.env*.local

CLAUDE.md
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@
},
"dependencies": {
"@apollo/client": "^3.10.8",
"@getpara/ethers-v5-integration": "2.0.0-alpha.64",
"@getpara/evm-wallet-connectors": "2.0.0-alpha.64",
"@getpara/react-sdk-lite": "2.0.0-alpha.64",
"@getpara/ethers-v5-integration": "2.0.0",
"@getpara/evm-wallet-connectors": "2.0.0",
"@getpara/react-sdk-lite": "2.0.0",
"@headlessui/react": "^1.7.18",
"@heroicons/react": "^2.1.4",
"@jbx-protocol/contracts-v1": "2.0.0",
Expand Down
18 changes: 9 additions & 9 deletions src/components/ProtocolActivity/ProtocolActivityElement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,17 @@ export function ProtocolActivityElement({
/>
</div>

{/* Row 2: Action Label + Amount */}
<div className="flex items-baseline gap-2 mb-1">
<span className="text-sm text-grey-600 dark:text-grey-400 capitalize">
{header}
</span>
<div className="font-heading text-lg whitespace-nowrap">
{subject}
</div>
{/* Row 2: Action Label */}
<div className="text-sm text-grey-600 dark:text-grey-400 capitalize mb-1">
{header}
</div>

{/* Row 3: Amount */}
<div className="font-heading text-lg whitespace-nowrap mb-1">
{subject}
</div>

{/* Row 3: Timestamp + From Address */}
{/* Row 4: Timestamp + From Address */}
<div className="flex items-center gap-2 text-xs text-grey-500 dark:text-grey-500">
<span>{formatHistoricalDate(event.timestamp * 1000)}</span>
<span>·</span>
Expand Down
54 changes: 11 additions & 43 deletions src/components/ProtocolActivity/ProtocolActivityList.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,37 @@
import { Button } from 'antd'
import Loading from 'components/Loading'
import { useActivityEventsQuery } from 'generated/v4v5/graphql'
import { testnetBendystrawClient, mainnetBendystrawClient } from 'lib/apollo/bendystrawClient'
import { mainnetBendystrawClient } from 'lib/apollo/bendystrawClient'
import {
AnyEvent,
transformEventData,
} from 'packages/v4v5/views/V4V5ProjectDashboard/V4V5ProjectTabs/V4V5ActivityPanel/utils/transformEventsData'
import React, { useState } from 'react'
import { twMerge } from 'tailwind-merge'
import Link from 'next/link'
import { v4v5ProjectRoute } from 'packages/v4v5/utils/routes'
import { ProtocolActivityElement } from './ProtocolActivityElement'
import { translateEventDataToProtocolPresenter } from './utils/translateEventDataToProtocolPresenter'

const PAGE_SIZE = 20
const POLL_INTERVAL = 30000 // 30 seconds

type NetworkType = 'testnet' | 'mainnet'

// Always default to mainnet first
const defaultNetwork: NetworkType = 'mainnet'
const IGNORED_EVENTS = ['mintNftEvent', 'burnEvent']
const baseEventFilter = IGNORED_EVENTS.reduce(
(acc, curr) => ({
...acc,
[curr]: null,
}),
{},
)

export function ProtocolActivityList() {
const [network, setNetwork] = useState<NetworkType>(defaultNetwork)
const [endCursor, setEndCursor] = useState<string | null>(null)

// Select client based on network toggle
const client = network === 'testnet' ? testnetBendystrawClient : mainnetBendystrawClient

// Reset cursor when network changes
React.useEffect(() => {
setEndCursor(null)
}, [network])

// Query protocol activity (no chain filter)
const { data: activityEvents, loading, error } = useActivityEventsQuery({
client,
client: mainnetBendystrawClient,
pollInterval: POLL_INTERVAL, // Poll every 30 seconds
variables: {
where: {},
where: baseEventFilter,
orderBy: 'timestamp',
orderDirection: 'desc',
after: endCursor,
Expand All @@ -65,31 +58,6 @@ export function ProtocolActivityList() {
<h2 className="mb-4 font-heading text-2xl font-medium">
Protocol Activity
</h2>
{/* Network Toggle */}
<div className="mb-4 flex gap-2">
<button
onClick={() => setNetwork('mainnet')}
className={twMerge(
'rounded-md px-4 py-2 text-sm font-medium transition-colors',
network === 'mainnet'
? 'bg-bluebs-500 text-white'
: 'bg-smoke-100 text-grey-600 hover:bg-smoke-200 dark:bg-slate-700 dark:text-slate-200 dark:hover:bg-slate-600',
)}
>
Mainnet
</button>
<button
onClick={() => setNetwork('testnet')}
className={twMerge(
'rounded-md px-4 py-2 text-sm font-medium transition-colors',
network === 'testnet'
? 'bg-bluebs-500 text-white'
: 'bg-smoke-100 text-grey-600 hover:bg-smoke-200 dark:bg-slate-700 dark:text-slate-200 dark:hover:bg-slate-600',
)}
>
Testnet
</button>
</div>
</div>
<div className="flex-1 overflow-y-auto px-6">
<div className="flex flex-col gap-3">
Expand Down
2 changes: 1 addition & 1 deletion src/components/VolumeChart/components/TimelineChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ export default function TimelineChart({
type="monotone"
dataKey={view}
activeDot={{ r: 6, fill: colors.juice[400], stroke: undefined }}
animationDuration={750}
isAnimationActive={false}
/>
)}
<Tooltip
Expand Down
2 changes: 2 additions & 0 deletions src/contexts/ProjectMetadataContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface ProjectMetadataContextType {
isArchived: boolean | undefined
projectId: number | undefined
pv: PV | undefined
isLoading: boolean
refetchProjectMetadata: VoidFunction
}

Expand All @@ -16,6 +17,7 @@ export const ProjectMetadataContext = createContext<ProjectMetadataContextType>(
isArchived: undefined,
projectId: undefined,
pv: undefined,
isLoading: true,
refetchProjectMetadata: () =>
console.error(
'ProjectMetadataContext.refetchProjectMetadata called but no provider set',
Expand Down
63 changes: 63 additions & 0 deletions src/locales/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ msgstr ""
msgid "An address"
msgstr ""

msgid "change"
msgstr ""

msgid "Activating this option enables running the user's wallet address against OFAC’s Specially Designated Nationals (SDN) list"
msgstr ""

Expand Down Expand Up @@ -1091,6 +1094,9 @@ msgstr ""
msgid "Edit project and cycle rules"
msgstr ""

msgid "Next cycle"
msgstr ""

msgid "Your project was successfully created!"
msgstr ""

Expand Down Expand Up @@ -1226,6 +1232,9 @@ msgstr ""
msgid "Choose an ENS name to use as the project's handle. Subdomains are allowed and will be included in the handle. Handles won't include the \".eth\" extension."
msgstr ""

msgid "Queue Safe ERC-20 Deploy Transactions"
msgstr ""

msgid "Total:"
msgstr ""

Expand Down Expand Up @@ -1265,6 +1274,9 @@ msgstr ""
msgid "Project tokens will be minted to the address that made the payment."
msgstr ""

msgid "You are viewing a past ruleset. This cycle has ended."
msgstr ""

msgid "Migrate legacy tokens"
msgstr ""

Expand Down Expand Up @@ -1331,6 +1343,9 @@ msgstr ""
msgid "Cash outs are disabled when all of the project's ETH is being used for payouts (when payouts are unlimited)."
msgstr ""

msgid "Started {0}"
msgstr ""

msgid "Fee from <0><1/></0>"
msgstr ""

Expand Down Expand Up @@ -1367,6 +1382,9 @@ msgstr ""
msgid "A fixed amount of ETH can be paid out from your project each ruleset. You can send specific ETH amounts (or ETH amounts based on USD values) to one or more recipients. Any remaining ETH will stay in your project for token cash outs or use in future rulesets."
msgstr ""

msgid "Past"
msgstr ""

msgid "Not able to process fees"
msgstr ""

Expand Down Expand Up @@ -1682,6 +1700,9 @@ msgstr ""
msgid "Reserved recipients:"
msgstr ""

msgid "Beginner Friendly"
msgstr ""

msgid "Transfer ownership"
msgstr ""

Expand Down Expand Up @@ -1748,6 +1769,9 @@ msgstr ""
msgid "This cycle's payouts"
msgstr ""

msgid "Since your project owner is a Gnosis Safe and this is an omnichain project, you need to queue separate ERC-20 deploy transactions on each chain."
msgstr ""

msgid "<0>This website interacts with the Ethereum blockchain — to use it, you'll need to have a wallet and some ETH (ETH is the main currency on Ethereum). You can get a free wallet from <1>MetaMask.io</1>, and buy ETH from within the wallet by using a credit card.</0>"
msgstr ""

Expand Down Expand Up @@ -2090,6 +2114,9 @@ msgstr ""
msgid "allocation"
msgstr ""

msgid "Token credits"
msgstr ""

msgid "This project's rules may pose risks for contributors:"
msgstr ""

Expand Down Expand Up @@ -2123,6 +2150,9 @@ msgstr ""
msgid "Edit NFTs"
msgstr ""

msgid "Confirm archive"
msgstr ""

msgid "{tokenSymbol} ERC-20 address"
msgstr ""

Expand Down Expand Up @@ -2234,6 +2264,9 @@ msgstr ""
msgid "Enable reserved tokens"
msgstr ""

msgid "This project's rules will be locked in place for {rulesetLength}."
msgstr ""

msgid "Case study"
msgstr ""

Expand Down Expand Up @@ -2516,6 +2549,9 @@ msgstr ""
msgid "Not a valid ETH address"
msgstr ""

msgid "Previous cycle"
msgstr ""

msgid "{0} after JBX fee"
msgstr ""

Expand Down Expand Up @@ -2612,6 +2648,9 @@ msgstr ""
msgid "reserved token recipient"
msgstr ""

msgid "Cashing out tokens"
msgstr ""

msgid "Controller configuration"
msgstr ""

Expand Down Expand Up @@ -2870,9 +2909,15 @@ msgstr ""
msgid "Redeem tokens"
msgstr ""

msgid "Load more cycles..."
msgstr ""

msgid "Add an on-chain note about this cycle."
msgstr ""

msgid "Changes from Cycle #{previousCycleNumber}"
msgstr ""

msgid "Archive project"
msgstr ""

Expand All @@ -2891,6 +2936,9 @@ msgstr ""
msgid "All of this project's ETH will be paid out. Token holders will receive <0>no ETH</0> when redeeming their tokens."
msgstr ""

msgid "Loading..."
msgstr ""

msgid "Approve"
msgstr ""

Expand Down Expand Up @@ -3575,6 +3623,9 @@ msgstr ""
msgid "Previous value"
msgstr ""

msgid "changes"
msgstr ""

msgid "No chains available for multi-chain deployment"
msgstr ""

Expand Down Expand Up @@ -3695,6 +3746,9 @@ msgstr ""
msgid "Reserve 1 NFT of every"
msgstr ""

msgid "Select cycle"
msgstr ""

msgid "NFT Projects"
msgstr ""

Expand Down Expand Up @@ -3977,6 +4031,9 @@ msgstr ""
msgid "Redeem {tokensLabel} for ETH"
msgstr ""

msgid "Past ruleset cycle"
msgstr ""

msgid "Made a mistake?"
msgstr ""

Expand Down Expand Up @@ -4445,6 +4502,9 @@ msgstr ""
msgid "Simple token rules that will work for most projects. You can edit these rules in future cycles."
msgstr ""

msgid "Confirm unarchive"
msgstr ""

msgid "Start"
msgstr ""

Expand Down Expand Up @@ -4556,6 +4616,9 @@ msgstr ""
msgid "ETH"
msgstr ""

msgid "Ruleset cycle"
msgstr ""

msgid "The amount of reserved tokens currently available to be distributed to the recipients below."
msgstr ""

Expand Down
3 changes: 3 additions & 0 deletions src/packages/v1/contexts/V1ProjectMetadataProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export function V1ProjectMetadataProvider({
metadata?.archived) ??
false

const isLoading = !metadata

return (
<ProjectMetadataContext.Provider
value={{
Expand All @@ -33,6 +35,7 @@ export function V1ProjectMetadataProvider({
isArchived,
projectId: projectId?.toNumber(),
pv: PV_V1,
isLoading,
}}
>
{children}
Expand Down
3 changes: 3 additions & 0 deletions src/packages/v2v3/contexts/V2V3ProjectMetadataProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@ export default function V2V3ProjectMetadataProvider({
projectMetadata?.archived) ??
false

const isLoading = !projectMetadata

return (
<ProjectMetadataContext.Provider
value={{
projectMetadata,
isArchived,
projectId,
pv: PV_V2,
isLoading,
refetchProjectMetadata: refetchValue,
}}
>
Expand Down
Loading
Loading