mirror of
https://github.com/MAGICGrants/campaign-site.git
synced 2026-01-09 12:27:59 -05:00
feat: re-add "donate" and add "get annual membership" buttons to project page
This commit is contained in:
@@ -32,10 +32,7 @@ const DonationFormModal: React.FC<Props> = ({ project }) => {
|
||||
.object({
|
||||
name: z.string().optional(),
|
||||
email: z.string().email().optional(),
|
||||
amount: z.coerce
|
||||
.number()
|
||||
.min(1)
|
||||
.max(MAX_AMOUNT / 100),
|
||||
amount: z.coerce.number().min(1).max(MAX_AMOUNT),
|
||||
taxDeductible: z.enum(['yes', 'no']),
|
||||
})
|
||||
.refine((data) => (!isAuthed && data.taxDeductible === 'yes' ? !!data.name : true), {
|
||||
|
||||
@@ -31,10 +31,7 @@ const MembershipFormModal: React.FC<Props> = ({ project }) => {
|
||||
.object({
|
||||
name: z.string().optional(),
|
||||
email: z.string().email().optional(),
|
||||
amount: z.coerce
|
||||
.number()
|
||||
.min(1)
|
||||
.max(MAX_AMOUNT / 100),
|
||||
amount: z.coerce.number().min(1).max(MAX_AMOUNT),
|
||||
taxDeductible: z.enum(['yes', 'no']),
|
||||
recurring: z.enum(['yes', 'no']),
|
||||
})
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
export const CURRENCY = 'usd'
|
||||
// Set your amount limits: Use float for decimal currencies and
|
||||
// Integer for zero-decimal currencies: https://stripe.com/docs/currencies#zero-decimal.
|
||||
export const MIN_AMOUNT = 100
|
||||
export const MAX_AMOUNT = 500000
|
||||
export const AMOUNT_STEP = 500
|
||||
export const MEMBERSHIP_PRICE = 10000
|
||||
export const MIN_AMOUNT = 1
|
||||
export const MAX_AMOUNT = 500
|
||||
export const AMOUNT_STEP = 5
|
||||
export const MEMBERSHIP_PRICE = 100
|
||||
|
||||
@@ -48,7 +48,7 @@ function MyDonations() {
|
||||
<TableCell>{donation.projectName}</TableCell>
|
||||
<TableCell>{donation.fund}</TableCell>
|
||||
<TableCell>{donation.btcPayInvoiceId ? 'Crypto' : 'Fiat'}</TableCell>
|
||||
<TableCell>${donation.fiatAmount / 100}</TableCell>
|
||||
<TableCell>${donation.fiatAmount}</TableCell>
|
||||
<TableCell>{dayjs(donation.createdAt).format('lll')}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
|
||||
@@ -64,9 +64,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
`stores/${env.BTCPAY_STORE_ID}/invoices/${body.invoiceId}/payment-methods`
|
||||
)
|
||||
|
||||
const fiatAmount = Math.round(
|
||||
Number(paymentMethods[0].amount) * Number(paymentMethods[0].rate) * 100
|
||||
)
|
||||
const cryptoAmount = Number(paymentMethods[0].amount)
|
||||
const fiatAmount = Number(paymentMethods[0].amount) * Number(paymentMethods[0].rate)
|
||||
|
||||
await prisma.donation.create({
|
||||
data: {
|
||||
@@ -76,6 +75,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
projectSlug: body.metadata.projectSlug,
|
||||
fund: 'Monero Fund',
|
||||
cryptoCode: paymentMethods[0].cryptoCode,
|
||||
cryptoAmount,
|
||||
fiatAmount,
|
||||
membershipExpiresAt:
|
||||
body.metadata.isMembership === 'true' ? dayjs().add(1, 'year').toDate() : null,
|
||||
|
||||
@@ -30,8 +30,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
return
|
||||
}
|
||||
|
||||
console.log(event.type)
|
||||
|
||||
// Store donation data when payment intent is valid
|
||||
// Subscriptions are handled on the invoice.paid event instead
|
||||
if (event.type === 'payment_intent.succeeded') {
|
||||
@@ -50,7 +48,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
projectName: metadata.projectName,
|
||||
projectSlug: metadata.projectSlug,
|
||||
fund: 'Monero Fund',
|
||||
fiatAmount: paymentIntent.amount_received,
|
||||
fiatAmount: paymentIntent.amount_received / 100,
|
||||
membershipExpiresAt:
|
||||
metadata.isMembership === 'true' ? dayjs().add(1, 'year').toDate() : null,
|
||||
},
|
||||
@@ -75,7 +73,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
projectName: metadata.projectName,
|
||||
projectSlug: metadata.projectSlug,
|
||||
fund: 'Monero Fund',
|
||||
fiatAmount: invoice.total,
|
||||
fiatAmount: invoice.total / 100,
|
||||
membershipExpiresAt: new Date(invoiceLine.period.end * 1000),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -5,8 +5,8 @@ import ErrorPage from 'next/error'
|
||||
import Image from 'next/image'
|
||||
import xss from 'xss'
|
||||
|
||||
import { ProjectItem, Stats } from '../../utils/types'
|
||||
import { getPostBySlug, getAllPosts } from '../../utils/md'
|
||||
import { ProjectDonationStats, ProjectItem } from '../../utils/types'
|
||||
import { getProjectBySlug, getAllPosts } from '../../utils/md'
|
||||
import markdownToHtml from '../../utils/markdownToHtml'
|
||||
import {
|
||||
fetchPostJSON,
|
||||
@@ -16,33 +16,24 @@ import {
|
||||
import PageHeading from '../../components/PageHeading'
|
||||
import SocialIcon from '../../components/social-icons'
|
||||
import Progress from '../../components/Progress'
|
||||
import { prisma } from '../../server/services'
|
||||
import { Button } from '../../components/ui/button'
|
||||
import { Dialog, DialogContent } from '../../components/ui/dialog'
|
||||
import DonationFormModal from '../../components/DonationFormModal'
|
||||
import MembershipFormModal from '../../components/MembershipFormModal'
|
||||
import Head from 'next/head'
|
||||
|
||||
type SingleProjectPageProps = {
|
||||
project: ProjectItem
|
||||
projects: ProjectItem[]
|
||||
stats: Stats
|
||||
donationStats: ProjectDonationStats
|
||||
}
|
||||
|
||||
const Project: NextPage<SingleProjectPageProps> = ({
|
||||
project,
|
||||
projects,
|
||||
stats,
|
||||
}) => {
|
||||
const Project: NextPage<SingleProjectPageProps> = ({ project, projects, donationStats }) => {
|
||||
const router = useRouter()
|
||||
|
||||
const [modalOpen, setModalOpen] = useState(false)
|
||||
|
||||
const [selectedProject, setSelectedProject] = useState<ProjectItem>()
|
||||
|
||||
function closeModal() {
|
||||
setModalOpen(false)
|
||||
}
|
||||
|
||||
function openPaymentModal() {
|
||||
console.log('opening single project modal...')
|
||||
setSelectedProject(project)
|
||||
setModalOpen(true)
|
||||
}
|
||||
const [donateModalOpen, setDonateModalOpen] = useState(false)
|
||||
const [memberModalOpen, setMemberModalOpen] = useState(false)
|
||||
|
||||
const {
|
||||
slug,
|
||||
@@ -81,8 +72,13 @@ const Project: NextPage<SingleProjectPageProps> = ({
|
||||
if (!router.isFallback && !slug) {
|
||||
return <ErrorPage statusCode={404} />
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Monero Fund - {project.title}</title>
|
||||
</Head>
|
||||
|
||||
<div className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<PageHeading project={project}>
|
||||
<div className="flex flex-col items-center space-x-2 pt-8 xl:block">
|
||||
@@ -95,13 +91,22 @@ const Project: NextPage<SingleProjectPageProps> = ({
|
||||
/>
|
||||
|
||||
<div className="space-y-4">
|
||||
{!project.isFunded && (
|
||||
<div className="flex flex-col space-y-2">
|
||||
<Button onClick={() => setDonateModalOpen(true)}>Donate</Button>
|
||||
<Button onClick={() => setMemberModalOpen(true)} variant="outline">
|
||||
Get Annual Membership
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<h1 className="mb-4 font-bold">Raised</h1>
|
||||
|
||||
<Progress
|
||||
percent={Math.floor(
|
||||
((stats[slug].xmr.totaldonationsinfiat +
|
||||
stats[slug].btc.totaldonationsinfiat +
|
||||
stats[slug].usd.totaldonationsinfiat) /
|
||||
((donationStats.xmr.fiatAmount +
|
||||
donationStats.btc.fiatAmount +
|
||||
donationStats.usd.fiatAmount) /
|
||||
goal) *
|
||||
100
|
||||
)}
|
||||
@@ -109,34 +114,28 @@ const Project: NextPage<SingleProjectPageProps> = ({
|
||||
|
||||
<ul className="font-semibold space-y-1">
|
||||
<li className="flex items-center space-x-1">
|
||||
<span className="text-green-500 text-xl">{`${formatUsd(stats[slug].xmr.totaldonationsinfiat + stats[slug].btc.totaldonationsinfiat + stats[slug].usd.totaldonationsinfiat)}`}</span>{' '}
|
||||
<span className="text-green-500 text-xl">{`${formatUsd(donationStats.xmr.fiatAmount + donationStats.btc.fiatAmount + donationStats.usd.fiatAmount)}`}</span>{' '}
|
||||
<span className="font-normal text-sm text-gray">
|
||||
in{' '}
|
||||
{stats[slug].xmr.numdonations +
|
||||
stats[slug].btc.numdonations +
|
||||
stats[slug].usd.numdonations}{' '}
|
||||
in {donationStats.xmr.count + donationStats.btc.count + donationStats.usd.count}{' '}
|
||||
donations total
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
{stats[slug].xmr.totaldonations} XMR{' '}
|
||||
{donationStats.xmr.amount} XMR{' '}
|
||||
<span className="font-normal text-sm text-gray">
|
||||
in {stats[slug].xmr.numdonations} {''}
|
||||
donations
|
||||
in {donationStats.xmr.count} donations
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
{stats[slug].btc.totaldonations} BTC{' '}
|
||||
{donationStats.btc.amount} BTC{' '}
|
||||
<span className="font-normal text-sm text-gray">
|
||||
in {stats[slug].btc.numdonations} {''}
|
||||
donations
|
||||
in {donationStats.btc.count} donations
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
{`${formatUsd(stats[slug].usd.totaldonations)}`} Fiat{' '}
|
||||
{`${formatUsd(donationStats.usd.amount)}`} Fiat{' '}
|
||||
<span className="font-normal text-sm text-gray">
|
||||
in {stats[slug].usd.numdonations} {''}
|
||||
donations
|
||||
in {donationStats.usd.count} donations
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -150,82 +149,17 @@ const Project: NextPage<SingleProjectPageProps> = ({
|
||||
</PageHeading>
|
||||
</div>
|
||||
|
||||
{/* <div className="flex flex-col items-center">
|
||||
<div
|
||||
className={
|
||||
'h-[15rem] w-full relative bg-gradient-to-b from-white to-gray-200'
|
||||
}
|
||||
>
|
||||
<Image
|
||||
alt={title}
|
||||
src={coverImage}
|
||||
layout="fill"
|
||||
objectFit="contain"
|
||||
objectPosition="50% 50%"
|
||||
/>
|
||||
</div>
|
||||
<Dialog open={donateModalOpen} onOpenChange={setDonateModalOpen}>
|
||||
<DialogContent>
|
||||
<DonationFormModal project={project} />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<div className="flex w-full p-4 py-8 md:px-8"></div>
|
||||
<article className="px-4 md:px-8 pb-8 lg:flex lg:flex-row-reverse lg:items-start">
|
||||
<div className={markdownStyles['markdown']}>
|
||||
|
||||
</div>
|
||||
|
||||
<aside className="p-4 bg-light rounded-xl flex lg:flex-col lg:items-start gap-4 min-w-[20rem] justify-between items-center mb-8">
|
||||
{isFunded ? `` : <button onClick={openPaymentModal}>Donate</button>}
|
||||
{stats && (
|
||||
<div>
|
||||
<h5>Raised</h5>
|
||||
<h4>{`${formatUsd(stats[slug].xmr.totaldonationsinfiat + stats[slug].btc.totaldonationsinfiat + stats[slug].usd.totaldonationsinfiat)}`}</h4>
|
||||
<h6>{stats[slug].xmr.totaldonations} XMR</h6>
|
||||
<h6>{stats[slug].btc.totaldonations} BTC</h6>
|
||||
<h6>{`${formatUsd(stats[slug].usd.totaldonations)}`} Fiat</h6>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{stats && (
|
||||
<div>
|
||||
<h5>Donations</h5>
|
||||
<h4>
|
||||
{stats[slug].xmr.numdonations +
|
||||
stats[slug].btc.numdonations +
|
||||
stats[slug].usd.numdonations}
|
||||
</h4>
|
||||
<h6>{stats[slug].xmr.numdonations} in XMR</h6>
|
||||
<h6>{stats[slug].btc.numdonations} in BTC</h6>
|
||||
<h6>{stats[slug].usd.numdonations} in Fiat</h6>
|
||||
|
||||
<Progress
|
||||
text={Math.floor(
|
||||
((stats[slug].xmr.totaldonationsinfiat +
|
||||
stats[slug].btc.totaldonationsinfiat +
|
||||
stats[slug].usd.totaldonationsinfiat) /
|
||||
goal) *
|
||||
100
|
||||
)}
|
||||
></Progress>
|
||||
</div>
|
||||
}
|
||||
</aside>
|
||||
</article>
|
||||
|
||||
<aside className="bg-light mb-8 flex min-w-[20rem] items-center justify-between gap-4 rounded-xl p-4 lg:flex-col lg:items-start">
|
||||
{!isFunded && (
|
||||
<button
|
||||
onClick={openPaymentModal}
|
||||
className="block rounded border border-stone-800 bg-stone-800 px-4 py-2 font-semibold text-white hover:border-transparent hover:bg-orange-500 hover:text-stone-800 dark:bg-white dark:text-black dark:hover:bg-orange-500"
|
||||
>
|
||||
Donate
|
||||
</button>
|
||||
)}
|
||||
</aside>
|
||||
</div> */}
|
||||
|
||||
{/* <PaymentModal
|
||||
isOpen={modalOpen}
|
||||
onRequestClose={closeModal}
|
||||
project={selectedProject}
|
||||
/> */}
|
||||
<Dialog open={memberModalOpen} onOpenChange={setMemberModalOpen}>
|
||||
<DialogContent>
|
||||
<MembershipFormModal project={project} />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -233,53 +167,59 @@ const Project: NextPage<SingleProjectPageProps> = ({
|
||||
export default Project
|
||||
|
||||
export async function getServerSideProps({ params }: { params: any }) {
|
||||
const post = getPostBySlug(params.slug)
|
||||
const project = getProjectBySlug(params.slug)
|
||||
const content = await markdownToHtml(project.content || '')
|
||||
|
||||
const projects = getAllPosts()
|
||||
const donationStats = {
|
||||
xmr: {
|
||||
count: project.isFunded ? project.numdonationsxmr : 0,
|
||||
amount: project.isFunded ? project.totaldonationsxmr : 0,
|
||||
fiatAmount: project.isFunded ? project.totaldonationsinfiatxmr : 0,
|
||||
},
|
||||
btc: {
|
||||
count: project.isFunded ? project.numdonationsbtc : 0,
|
||||
amount: project.isFunded ? project.totaldonationsbtc : 0,
|
||||
fiatAmount: project.isFunded ? project.totaldonationsinfiatbtc : 0,
|
||||
},
|
||||
usd: {
|
||||
count: project.isFunded ? project.fiatnumdonations : 0,
|
||||
amount: project.isFunded ? project.fiattotaldonations : 0,
|
||||
fiatAmount: project.isFunded ? project.fiattotaldonationsinfiat : 0,
|
||||
},
|
||||
}
|
||||
|
||||
const content = await markdownToHtml(post.content || '')
|
||||
if (!project.isFunded) {
|
||||
const donations = await prisma.donation.findMany({ where: { projectSlug: params.slug } })
|
||||
|
||||
let stats: any = {}
|
||||
|
||||
for (let i = 0; i < projects.length; i++) {
|
||||
let xmr
|
||||
let btc
|
||||
let usd
|
||||
|
||||
if (projects[i].isFunded) {
|
||||
xmr = {
|
||||
numdonations: projects[i].numdonationsxmr,
|
||||
totaldonationsinfiat: projects[i].totaldonationsinfiatxmr,
|
||||
totaldonations: projects[i].totaldonationsxmr,
|
||||
donations.forEach((donation) => {
|
||||
if (donation.cryptoCode === 'XMR') {
|
||||
donationStats.xmr.count += 1
|
||||
donationStats.xmr.amount += donation.cryptoAmount
|
||||
donationStats.xmr.fiatAmount += donation.fiatAmount
|
||||
}
|
||||
btc = {
|
||||
numdonations: projects[i].numdonationsbtc,
|
||||
totaldonationsinfiat: projects[i].totaldonationsinfiatbtc,
|
||||
totaldonations: projects[i].totaldonationsbtc,
|
||||
}
|
||||
usd = {
|
||||
numdonations: projects[i].fiatnumdonations,
|
||||
totaldonationsinfiat: projects[i].fiattotaldonationsinfiat,
|
||||
totaldonations: projects[i].fiattotaldonations,
|
||||
}
|
||||
} else {
|
||||
const crypto = await fetchGetJSONAuthedBTCPay(projects[i].slug)
|
||||
xmr = await crypto.xmr
|
||||
btc = await crypto.btc
|
||||
usd = await fetchGetJSONAuthedStripe(projects[i].slug)
|
||||
}
|
||||
|
||||
stats[projects[i].slug] = { xmr, btc, usd }
|
||||
if (donation.cryptoCode === 'BTC') {
|
||||
donationStats.btc.count += 1
|
||||
donationStats.btc.amount += donation.cryptoAmount
|
||||
donationStats.btc.fiatAmount += donation.fiatAmount
|
||||
}
|
||||
|
||||
if (donation.cryptoCode === null) {
|
||||
donationStats.usd.count += 1
|
||||
donationStats.usd.amount += donation.fiatAmount
|
||||
donationStats.usd.fiatAmount += donation.fiatAmount
|
||||
console.log(donation)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
project: {
|
||||
...post,
|
||||
...project,
|
||||
content,
|
||||
},
|
||||
projects,
|
||||
stats,
|
||||
donationStats,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@ CREATE TABLE "Donation" (
|
||||
"projectSlug" TEXT NOT NULL,
|
||||
"projectName" TEXT NOT NULL,
|
||||
"fund" TEXT NOT NULL,
|
||||
"fiatAmount" INTEGER NOT NULL,
|
||||
"cryptoCode" TEXT,
|
||||
"fiatAmount" DOUBLE PRECISION NOT NULL,
|
||||
"cryptoAmount" DOUBLE PRECISION,
|
||||
"membershipExpiresAt" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "Donation_pkey" PRIMARY KEY ("id")
|
||||
@@ -26,8 +26,9 @@ model Donation {
|
||||
projectSlug String
|
||||
projectName String
|
||||
fund String
|
||||
fiatAmount Int
|
||||
cryptoCode String?
|
||||
fiatAmount Float
|
||||
cryptoAmount Float?
|
||||
membershipExpiresAt DateTime?
|
||||
|
||||
@@index([stripePaymentIntentId])
|
||||
|
||||
@@ -19,10 +19,7 @@ export const donationRouter = router({
|
||||
email: z.string().email().nullable(),
|
||||
projectName: z.string().min(1),
|
||||
projectSlug: z.string().min(1),
|
||||
amount: z
|
||||
.number()
|
||||
.min(MIN_AMOUNT / 100)
|
||||
.max(MAX_AMOUNT / 100),
|
||||
amount: z.number().min(MIN_AMOUNT).max(MAX_AMOUNT),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
@@ -99,10 +96,7 @@ export const donationRouter = router({
|
||||
email: z.string().trim().email().nullable(),
|
||||
projectName: z.string().min(1),
|
||||
projectSlug: z.string().min(1),
|
||||
amount: z
|
||||
.number()
|
||||
.min(MIN_AMOUNT / 100)
|
||||
.max(MAX_AMOUNT / 100),
|
||||
amount: z.number().min(MIN_AMOUNT).max(MAX_AMOUNT),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
@@ -284,7 +278,7 @@ export const donationRouter = router({
|
||||
}
|
||||
|
||||
const response = await btcpayApi.post(`/stores/${env.BTCPAY_STORE_ID}/invoices`, {
|
||||
amount: MEMBERSHIP_PRICE / 100,
|
||||
amount: MEMBERSHIP_PRICE,
|
||||
currency: CURRENCY,
|
||||
metadata,
|
||||
checkout: { redirectURL: `${env.APP_URL}/thankyou` },
|
||||
|
||||
@@ -38,11 +38,7 @@ export async function fetchPostJSON(url: string, data?: {}) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchPostJSONAuthed(
|
||||
url: string,
|
||||
auth: string,
|
||||
data?: {}
|
||||
) {
|
||||
export async function fetchPostJSONAuthed(url: string, auth: string, data?: {}) {
|
||||
try {
|
||||
// Default options are marked with *
|
||||
const response = await fetch(url, {
|
||||
@@ -86,10 +82,7 @@ export async function fetchGetJSONAuthedBTCPay(slug: string) {
|
||||
let totaldonationsinfiatxmr = 0
|
||||
let totaldonationsinfiatbtc = 0
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (
|
||||
data[i].metadata.orderId != slug &&
|
||||
data[i].metadata.orderId != `${slug}_STATIC`
|
||||
) {
|
||||
if (data[i].metadata.orderId != slug && data[i].metadata.orderId != `${slug}_STATIC`) {
|
||||
continue
|
||||
}
|
||||
const id = data[i].id
|
||||
@@ -103,23 +96,15 @@ export async function fetchGetJSONAuthedBTCPay(slug: string) {
|
||||
},
|
||||
})
|
||||
const dataiter = await responseiter.json()
|
||||
if (
|
||||
dataiter[1].cryptoCode == 'XMR' &&
|
||||
dataiter[1].paymentMethodPaid > 0
|
||||
) {
|
||||
if (dataiter[1].cryptoCode == 'XMR' && dataiter[1].paymentMethodPaid > 0) {
|
||||
numdonationsxmr += dataiter[1].payments.length
|
||||
totaldonationsxmr += Number(dataiter[1].paymentMethodPaid)
|
||||
totaldonationsinfiatxmr +=
|
||||
Number(dataiter[1].paymentMethodPaid) * Number(dataiter[1].rate)
|
||||
totaldonationsinfiatxmr += Number(dataiter[1].paymentMethodPaid) * Number(dataiter[1].rate)
|
||||
}
|
||||
if (
|
||||
dataiter[0].cryptoCode == 'BTC' &&
|
||||
dataiter[0].paymentMethodPaid > 0
|
||||
) {
|
||||
if (dataiter[0].cryptoCode == 'BTC' && dataiter[0].paymentMethodPaid > 0) {
|
||||
numdonationsbtc += dataiter[0].payments.length
|
||||
totaldonationsbtc += Number(dataiter[0].paymentMethodPaid)
|
||||
totaldonationsinfiatbtc +=
|
||||
Number(dataiter[0].paymentMethodPaid) * Number(dataiter[0].rate)
|
||||
totaldonationsinfiatbtc += Number(dataiter[0].paymentMethodPaid) * Number(dataiter[0].rate)
|
||||
}
|
||||
}
|
||||
return await {
|
||||
@@ -158,10 +143,7 @@ export async function fetchGetJSONAuthedStripe(slug: string) {
|
||||
let total = 0
|
||||
let donations = 0
|
||||
for (let i = 0; i < dataext.length; i++) {
|
||||
if (
|
||||
dataext[i].metadata.project_slug == null ||
|
||||
dataext[i].metadata.project_slug != slug
|
||||
) {
|
||||
if (dataext[i].metadata.project_slug == null || dataext[i].metadata.project_slug != slug) {
|
||||
continue
|
||||
}
|
||||
total += Number(dataext[i].amount) / 100
|
||||
|
||||
@@ -5,7 +5,8 @@ import sanitize from 'sanitize-filename'
|
||||
|
||||
const postsDirectory = join(process.cwd(), 'docs/projects')
|
||||
|
||||
const FIELDS = ['title',
|
||||
const FIELDS = [
|
||||
'title',
|
||||
'summary',
|
||||
'slug',
|
||||
'git',
|
||||
@@ -40,8 +41,8 @@ export function getSingleFile(path: string) {
|
||||
return fs.readFileSync(fullPath, 'utf8')
|
||||
}
|
||||
|
||||
export function getPostBySlug(slug: string) {
|
||||
const fields = FIELDS;
|
||||
export function getProjectBySlug(slug: string) {
|
||||
const fields = FIELDS
|
||||
const realSlug = slug.replace(/\.md$/, '')
|
||||
const fullPath = join(postsDirectory, `${sanitize(realSlug)}.md`)
|
||||
const fileContents = fs.readFileSync(fullPath, 'utf8')
|
||||
@@ -68,7 +69,7 @@ export function getPostBySlug(slug: string) {
|
||||
|
||||
export function getAllPosts() {
|
||||
const slugs = getPostSlugs()
|
||||
const posts = slugs.map((slug) => getPostBySlug(slug))
|
||||
const posts = slugs.map((slug) => getProjectBySlug(slug))
|
||||
|
||||
return posts
|
||||
}
|
||||
|
||||
@@ -33,4 +33,20 @@ export type PayReq = {
|
||||
name?: string
|
||||
}
|
||||
|
||||
export type Stats = any
|
||||
export type ProjectDonationStats = {
|
||||
xmr: {
|
||||
count: number
|
||||
amount: number
|
||||
fiatAmount: number
|
||||
}
|
||||
btc: {
|
||||
count: number
|
||||
amount: number
|
||||
fiatAmount: number
|
||||
}
|
||||
usd: {
|
||||
count: number
|
||||
amount: number
|
||||
fiatAmount: number
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user