Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a9bc946
feat: add referral link generation feature with analytics tracking
fr1jo Oct 3, 2025
619d377
feat: add referral rewards info to Swap rewards tooltip
fr1jo Oct 3, 2025
5e4bb9b
feat: enhance referral link UX with real-time copy feedback and impro…
fr1jo Oct 3, 2025
db9241e
feat: improve referral page styling and add progress bar
fr1jo Oct 3, 2025
a7f7a37
fix: improve referral link input width and layout
fr1jo Oct 4, 2025
6926830
refactor: remove redundant section and rebrand beans to pinto
fr1jo Oct 4, 2025
a2d7562
feat: separate leaderboard and improve referral stats display
fr1jo Oct 4, 2025
94551f1
fix: update referral bonus to 10% and clarify only referrer earns
fr1jo Oct 4, 2025
a049d72
refactor: capitalize Sow, remove CTA, and improve stats layout
fr1jo Oct 4, 2025
b32e59c
feat: improve referral link UX with disabled state
fr1jo Oct 4, 2025
6dde858
feat: reorder navigation - move Referral after Pod Market
fr1jo Oct 4, 2025
ea9872e
chore: apply Biome formatting to referral components
fr1jo Oct 4, 2025
5c06e1c
feat: reorder qualification progress to appear above link input
fr1jo Oct 4, 2025
a326ccf
Change referral layout
feyyazcigim Nov 22, 2025
25eb501
Implement referral system to UI
feyyazcigim Dec 1, 2025
00d89a6
Merge branch 'main' into frijo/feat/sowreferral
feyyazcigim Dec 10, 2025
ed169c4
Change gql implementations
feyyazcigim Dec 10, 2025
0d1aa5c
Refactor delegate address modal
feyyazcigim Dec 10, 2025
aaaf507
Refactor referral table
feyyazcigim Dec 10, 2025
d9f56f5
Refactor graphql queries
feyyazcigim Dec 15, 2025
0680afc
Add eligibility check
feyyazcigim Dec 15, 2025
5306dda
Clear unnecessary comments
feyyazcigim Dec 15, 2025
aec3acb
Improve transaction handling
feyyazcigim Dec 18, 2025
99944d9
Use standardized UI components and make implementation modular
feyyazcigim Dec 18, 2025
69cb97e
Merge branch 'main' into frijo/feat/sowreferral
burr-nim Dec 22, 2025
e4f9456
Make visual updates to referral page components
feyyazcigim Dec 29, 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
9 changes: 9 additions & 0 deletions src/ProtectedLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Explorer from "./pages/Explorer";
import Field from "./pages/Field";
import { Market as MarketPage } from "./pages/Market";
import Overview from "./pages/Overview";
import Referral from "./pages/Referral";
import Silo from "./pages/Silo";
import SiloToken from "./pages/SiloToken";
import Swap from "./pages/Swap";
Expand Down Expand Up @@ -60,6 +61,14 @@ export default function ProtectedLayout() {
</PageMetaWrapper>
}
/>
<Route
path="/referral"
element={
<PageMetaWrapper metaKey="referral">
<Referral />
</PageMetaWrapper>
}
/>
<Route
path="/market/pods"
element={
Expand Down
Binary file added src/assets/misc/telegram-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/misc/x-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
160 changes: 160 additions & 0 deletions src/components/DelegateReferralModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import { Col, Row } from "@/components/Container";
import { Button } from "@/components/ui/Button";
import { Input } from "@/components/ui/Input";
import { Label } from "@/components/ui/Label";
import { beanstalkAbi, beanstalkAddress } from "@/generated/contractHooks";
import useTransaction from "@/hooks/useTransaction";
import { Cross2Icon } from "@radix-ui/react-icons";
import { useState } from "react";
import { toast } from "sonner";
import { isAddress } from "viem";
import { useChainId } from "wagmi";

interface DelegateReferralModalProps {
isOpen: boolean;
onOpenChange: (open: boolean) => void;
}

export function DelegateReferralModal({ isOpen, onOpenChange }: DelegateReferralModalProps) {
const [delegateAddress, setDelegateAddress] = useState("");
const [error, setError] = useState("");
const chainId = useChainId();

// Check if address is valid
const isValidAddress = delegateAddress.trim() && isAddress(delegateAddress);

// Transaction handling
const { writeWithEstimateGas, setSubmitting, isConfirming } = useTransaction({
successCallback: () => {
setDelegateAddress("");
onOpenChange(false);
},
successMessage: "Delegate address updated successfully",
errorMessage: "Failed to update delegate address",
});

const handleSubmit = async () => {
// Validate address
if (!delegateAddress.trim()) {
setError("Please enter an address");
return;
}

if (!isAddress(delegateAddress)) {
setError("Invalid Ethereum address");
return;
}

setError("");

try {
setSubmitting(true);
toast.loading("Updating delegate address");

await writeWithEstimateGas({
address: beanstalkAddress[chainId as keyof typeof beanstalkAddress],
abi: beanstalkAbi,
functionName: "delegateReferralRewards",
args: [delegateAddress as `0x${string}`],
});
} catch (e) {
console.error("Failed to update delegate address:", e);
toast.dismiss();
toast.error("Failed to update delegate address");
} finally {
setSubmitting(false);
}
};

const handleReset = async () => {
setError("");

try {
setSubmitting(true);
toast.loading("Resetting delegate address...");

await writeWithEstimateGas({
address: beanstalkAddress[chainId as keyof typeof beanstalkAddress],
abi: beanstalkAbi,
functionName: "delegateReferralRewards",
args: ["0x0000000000000000000000000000000000000000" as `0x${string}`],
});
} catch (e) {
console.error("Failed to reset delegate address:", e);
toast.dismiss();
toast.error("Failed to reset delegate address");
} finally {
setSubmitting(false);
}
};

if (!isOpen) return null;

return (
<Col className="h-auto w-full">
<div className="flex flex-col gap-6">
{/* Title and separator */}
<div className="flex flex-col gap-2">
<div className="flex justify-between items-start">
<div className="pinto-body font-medium text-pinto-secondary mb-4">📍 Change Pod Destination Address</div>
<button
type="button"
onClick={() => onOpenChange(false)}
className="text-pinto-light hover:text-pinto-dark transition-colors p-1 -mt-1 -mr-1"
>
<Cross2Icon className="w-4 h-4" />
</button>
</div>
<div className="h-[1px] w-full bg-pinto-gray-2" />
</div>

{/* Form Section */}
<Col className="gap-6 pinto-sm-light text-pinto-light">
<div className="flex flex-col gap-2">
<Label variant="form">Delegate Address</Label>
<Input
value={delegateAddress}
onChange={(e) => {
setDelegateAddress(e.target.value);
setError("");
}}
placeholder="0x..."
outlined
/>
{error && <span className="pinto-sm text-pinto-red-2">{error}</span>}
</div>

<div className="pinto-sm-light text-pinto-light">
Enter the address where you want your referral reward Pods to be sent.
</div>
</Col>

{/* Action Buttons */}
<Row className="gap-4 w-full">
<Button
onClick={handleReset}
variant="outline"
size="xlargest"
rounded="full"
disabled={isConfirming}
className="w-full flex-1 text-pinto-light bg-pinto-gray-1"
>
Reset Delegate
</Button>

<Button
onClick={handleSubmit}
size="xlargest"
rounded="full"
disabled={isConfirming || !isValidAddress}
className={`w-full flex-1 ${
isConfirming ? "bg-pinto-gray-2 text-pinto-light" : "bg-pinto-green-4 text-white"
}`}
>
{isConfirming ? "Confirming..." : "Update Delegate"}
</Button>
</Row>
</div>
</Col>
);
}
35 changes: 35 additions & 0 deletions src/components/HowToCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { StepItem } from "./ui/StepItem";

const steps = [
{
title: "Qualify as a Referrer",
description: "Sow at least 1,000 Pinto in the Field to unlock your referral link.",
},
{
title: "Share Your Link",
description: "Copy your unique referral link and share it with friends, on social media, or anywhere else.",
},
{
title: "Earn Rewards",
description:
"When someone uses your link and Sows Pinto, you earn 10% of the Pods they receive as a referral bonus.",
},
{
title: "Get Credited",
description:
"Referral rewards are automatically credited to your wallet address when your referral completes their Sow transaction.",
},
];

export function HowToCard() {
return (
<div className="space-y-4">
<div className="pinto-h3 sm:pinto-h2">How It Works</div>
<div className="space-y-3">
{steps.map((step, index) => (
<StepItem key={index} stepNumber={index + 1} title={step.title} description={step.description} />
))}
</div>
</div>
);
}
Loading