feat: ko-fi integration for credit purchases

This commit is contained in:
2026-04-23 11:59:05 -04:00
parent 4a68cc85f3
commit 3dcece5c67
4 changed files with 233 additions and 0 deletions
@@ -0,0 +1,86 @@
"use client";
import { Coffee, ExternalLink, X } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
interface BuyCreditsModalProps {
open: boolean;
onOpenChange: (open: boolean) => void;
}
const PRESETS = [
{ dollars: 5, credits: 500, label: "Small Feed", emoji: "🌾" },
{ dollars: 10, credits: 1000, label: "Big Feed", emoji: "🌽" },
{ dollars: 20, credits: 2000, label: "Feast", emoji: "🍗" },
];
export function BuyCreditsModal({ open, onOpenChange }: BuyCreditsModalProps) {
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="rounded-[2rem] border-4 border-foreground bg-card p-0 shadow-[12px_12px_0px_0px_rgba(0,0,0,0.1)] max-w-md">
<DialogHeader className="bg-primary/10 border-b-4 border-foreground p-6">
<div className="flex items-center justify-between">
<DialogTitle className="font-display text-3xl uppercase italic text-primary">
Stock the Coop
</DialogTitle>
<button
onClick={() => onOpenChange(false)}
className="rounded-full p-2 hover:bg-background transition-colors"
>
<X className="h-6 w-6" />
</button>
</div>
<p className="text-sm font-bold text-muted-foreground mt-2">
100 $COOP per dollar. Use same email as Plex for auto-delivery.
</p>
</DialogHeader>
<div className="p-6 space-y-4">
{PRESETS.map((preset) => (
<a
key={preset.dollars}
href={`https://ko-fi.com/dustinnewkirk`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-between rounded-2xl border-4 border-foreground bg-accent/10 p-4 shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] hover:translate-x-[2px] hover:translate-y-[2px] hover:shadow-none transition-all"
onClick={() => onOpenChange(false)}
>
<div className="flex items-center gap-4">
<span className="text-3xl">{preset.emoji}</span>
<div>
<div className="font-black text-lg">{preset.label}</div>
<div className="text-sm font-bold text-muted-foreground">
${preset.dollars} {preset.credits} $COOP
</div>
</div>
</div>
<ExternalLink className="h-5 w-5 text-muted-foreground" />
</a>
))}
<div className="rounded-2xl border-2 border-dashed border-foreground/30 bg-background p-4 text-center">
<p className="text-xs font-bold text-muted-foreground uppercase tracking-widest">
Any amount works. $1 = 100 $COOP.
</p>
<a
href="https://ko-fi.com/dustinnewkirk"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 mt-3 rounded-full bg-[#FF5E5B] px-6 py-3 font-black text-white shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] hover:translate-x-[2px] hover:translate-y-[2px] hover:shadow-none transition-all"
onClick={() => onOpenChange(false)}
>
<Coffee className="h-5 w-5" />
Support on Ko-fi
</a>
</div>
</div>
</DialogContent>
</Dialog>
);
}
+12
View File
@@ -2,6 +2,7 @@
import {
Activity,
Coffee,
Egg,
ExternalLink,
History,
@@ -19,6 +20,7 @@ import { api, authApi, overseerApi, userApi } from "@/lib/api";
import { useStore } from "@/lib/store";
import { formatNumber } from "@/lib/utils";
import { ActivityFeed } from "./components/ActivityFeed";
import { BuyCreditsModal } from "./components/BuyCreditsModal";
import { Leaderboard } from "./components/Leaderboard";
import { RequestHistory } from "./components/RequestHistory";
import { SearchRequestModal } from "./components/SearchRequestModal";
@@ -38,6 +40,7 @@ export default function DashboardPage() {
const [pendingRequests, setPendingRequests] = useState<any[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [isSearchModalOpen, setIsSearchModalOpen] = useState(false);
const [isBuyModalOpen, setIsBuyModalOpen] = useState(false);
useEffect(() => {
if (!isAuthenticated) {
@@ -122,6 +125,14 @@ export default function DashboardPage() {
<Search className="mr-2 h-5 w-5" />
PECK FOR FEED
</Button>
<Button
variant="outline"
onClick={() => setIsBuyModalOpen(true)}
className="rounded-full border-2 border-[#FF5E5B] bg-background font-bold text-[#FF5E5B] hover:bg-[#FF5E5B]/10"
>
<Coffee className="mr-2 h-5 w-5" />
BUY FEED
</Button>
<Button
variant="outline"
onClick={handleRefresh}
@@ -258,6 +269,7 @@ export default function DashboardPage() {
onOpenChange={setIsSearchModalOpen}
costs={requestCosts}
/>
<BuyCreditsModal open={isBuyModalOpen} onOpenChange={setIsBuyModalOpen} />
</div>
);
}