Skip to content

Commit

Permalink
Latest sponsor
Browse files Browse the repository at this point in the history
  • Loading branch information
pomber committed Dec 22, 2024
1 parent 1e15b06 commit e13a3df
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 1 deletion.
18 changes: 18 additions & 0 deletions apps/web/app/api/sponsors-webhook/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { revalidatePath } from "next/cache"

export async function POST(request: Request) {
try {
const text = await request.text()
console.log("[GitHub] Webhook received", text)

revalidatePath("/test")
} catch (error: any) {
return new Response(`Webhook error: ${error.message}`, {
status: 400,
})
}

return new Response("Success!", {
status: 200,
})
}
95 changes: 95 additions & 0 deletions apps/web/app/landing/sponsors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import Image from "next/image"
import Link from "next/link"
import sponsorData from "./sponsors.json"
import { Check, CheckCheck, GithubIcon, Heart, Star } from "lucide-react"
import { cn } from "@/lib/utils"
import { TimeAgo } from "@/components/time-ago"

export function Pricing() {
const current = 625
Expand Down Expand Up @@ -84,6 +86,65 @@ export function Pricing() {
)
}

export async function LatestSponsor({ className }: { className?: string }) {
const GITHUB_TOKEN = process.env.GITHUB_TOKEN
if (!GITHUB_TOKEN) {
throw new Error("Missing process.env.GITHUB_TOKEN")
}

const r = await fetch("https://api.github.com/graphql", {
method: "POST",
body: JSON.stringify({ query: latestSponsorsQuery }),
headers: { Authorization: "bearer " + GITHUB_TOKEN },
})
if (!r.ok) {
throw new Error(`Failed to fetch: ${r.status} ${r.statusText}`)
}
const { data, errors } = await r.json()
if (errors) {
throw new Error(JSON.stringify(errors))
}

const sponsors = data.organization.sponsorshipsAsMaintainer.edges
if (!sponsors.length) {
throw new Error("No sponsors found")
}

const latest = sponsors[0].node

return (
<a
href={`https://github.com/${latest.sponsorEntity.login}`}
className={cn(
className,
"rounded bg-zinc-50 dark:bg-zinc-900 p-3 flex gap-3 border border-zinc-200/50 dark:border-zinc-700/50 hover:border-zinc-200 dark:hover:border-zinc-700 transition-colors w-96 md:w-full mx-auto",
)}
>
<Image
className="rounded my-0 max-h-20"
src={`${latest.sponsorEntity.avatarUrl}`}
alt={latest.sponsorEntity.name}
height={80}
width={80}
placeholder="empty"
/>
<div className="flex-1 flex flex-col justify-between">
{/* <div>{new Date().toString()}</div> */}
<div className="text-primary/70 text-sm">
Latest sponsor · <TimeAgo date={latest.createdAt} />
</div>
<div className="text-2xl font-bold">
{latest.sponsorEntity.name || latest.sponsorEntity.login}
</div>
<div className="text-primary/90 text-sm">
Sponsoring <strong>{latest.tier.name}</strong>{" "}
</div>
</div>
{/* <pre>{JSON.stringify(latest, null, 2)}</pre> */}
</a>
)
}

export function TopSponsors({
title = "Top Sponsors",
scale = 1,
Expand Down Expand Up @@ -440,3 +501,37 @@ function BrowserStack() {
</svg>
)
}

const latestSponsorsQuery = `query {
organization(login: "code-hike") {
sponsorshipsAsMaintainer(first: 50, orderBy: {field: CREATED_AT, direction: DESC}, activeOnly: false) {
edges {
node {
createdAt
privacyLevel
tier {
name
monthlyPriceInDollars
}
sponsorEntity {
... on User {
login
name
avatarUrl
websiteUrl
location
}
... on Organization {
login
name
avatarUrl
websiteUrl
location
}
}
}
}
}
}
}
`
5 changes: 4 additions & 1 deletion apps/web/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Link from "next/link"
import {
AllSponsors,
LatestSponsor,
PoweredBy,
Pricing,
TopSponsors,
Expand Down Expand Up @@ -38,7 +39,9 @@ export default function HomePage() {

<Pricing />

<AllSponsors className="mb-24" title="Sponsors" />
<h3 className="text-center pb-8 text-primary/60 text-lg">Sponsors</h3>
<LatestSponsor className="mb-2" />
<AllSponsors cta="Become a sponsor" className="mb-24" />

<PoweredBy className="mb-8 text-center flex items-center justify-center gap-4 w-full flex-wrap" />
</main>
Expand Down
3 changes: 3 additions & 0 deletions apps/web/app/test/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { LatestSponsor } from "../landing/sponsors"
import Content from "./content.md"
import { Code } from "@/components/code"

export default function Page() {
return (
<div className="m-4 prose">
<div>{new Date().toString()}</div>
<LatestSponsor />
<Content components={{ Code }} />
</div>
)
Expand Down
45 changes: 45 additions & 0 deletions apps/web/components/time-ago.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"use client"

export function TimeAgo({ date }: { date: string }) {
const time = new Date(date)
return (
<time dateTime={time.toString()} title={time.toString()}>
{getTimeAgo(time)}
</time>
)
}

const MINUTE = 60
const HOUR = MINUTE * 60
const DAY = HOUR * 24
const WEEK = DAY * 7
const MONTH = DAY * 30
const YEAR = DAY * 365

function getTimeAgo(date: Date) {
const secondsAgo = Math.round((Date.now() - Number(date)) / 1000)

if (secondsAgo < MINUTE) {
return secondsAgo + ` second${secondsAgo !== 1 ? "s" : ""} ago`
}

let divisor
let unit = ""

if (secondsAgo < HOUR) {
;[divisor, unit] = [MINUTE, "minute"]
} else if (secondsAgo < DAY) {
;[divisor, unit] = [HOUR, "hour"]
} else if (secondsAgo < WEEK) {
;[divisor, unit] = [DAY, "day"]
} else if (secondsAgo < MONTH) {
;[divisor, unit] = [WEEK, "week"]
} else if (secondsAgo < YEAR) {
;[divisor, unit] = [MONTH, "month"]
} else {
;[divisor, unit] = [YEAR, "year"]
}

const count = Math.floor(secondsAgo / divisor)
return `${count} ${unit}${count > 1 ? "s" : ""} ago`
}
6 changes: 6 additions & 0 deletions apps/web/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ const config = {
port: "",
pathname: "/**",
},
{
protocol: "https",
hostname: "avatars.githubusercontent.com",
port: "",
pathname: "/**",
},
],
},
}
Expand Down

0 comments on commit e13a3df

Please sign in to comment.