Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Active grants section #46

Merged
merged 8 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
54 changes: 54 additions & 0 deletions packages/nextjs/app/_components/ActiveGrants.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Image from "next/image";
import { Address } from "~~/components/scaffold-eth";
import { getAllActiveGrants } from "~~/services/database/grants";
import { GrantData } from "~~/services/database/schema";
import { formatDateFromNow } from "~~/utils/grants";

const ActiveGrantRow = ({ title, askAmount, builder, approvedAt }: GrantData) => {
return (
<tr className="border-b border-black p-10 text-base">
<td className="p-4 pl-4">{title}</td>
<td className="p-4 pl-4">{askAmount} ETH</td>
<td className="p-4 pl-4">
<Address address={builder} />
</td>
<td className="p-4 pl-4">{approvedAt ? formatDateFromNow(approvedAt) : "-"}</td>
</tr>
);
};

export const ActiveGrants = async () => {
const activeGrants = await getAllActiveGrants();

if (!activeGrants.length) {
return null;
}

return (
<div className="container flex flex-col justify-center max-w-[90%] xl:max-w-7xl mx-auto py-16 gap-4">
<div className="self-center lg:self-start w-fit relative">
<h2 className="text-4xl lg:text-6xl text-center lg:text-left font-ppEditorial">WIP grants</h2>
<Image className="absolute -top-3 -right-7" src="/assets/sparkle.png" alt="sparkle" width={32} height={32} />
</div>
<div className="bg-base-100 rounded-3xl px-2 sm:px-6 pt-2 pb-6">
<div className="overflow-x-auto">
<table className="table">
<thead>
<tr className="border-b border-black text-black text-base">
<th>Title</th>
<th>Funding</th>
<th>Builder</th>
<th>Date</th>
</tr>
</thead>
<tbody className="">
{activeGrants.map(grant => (
<ActiveGrantRow key={grant.id} {...grant} />
))}
</tbody>
</table>
</div>
</div>
</div>
);
};
2 changes: 2 additions & 0 deletions packages/nextjs/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ActiveGrants } from "./_components/ActiveGrants";
import { CommunityGrant } from "./_components/CommunityGrant";
import { CompletedGrants } from "./_components/CompletedGrants";
import { EcosystemGrants } from "./_components/EcosystemGrants";
Expand All @@ -12,6 +13,7 @@ const Home = () => {
<EcosystemGrants />
<CommunityGrant />
<CompletedGrants />
<ActiveGrants />
</>
);
};
Expand Down
14 changes: 14 additions & 0 deletions packages/nextjs/services/database/grants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,20 @@ export const getAllCompletedGrants = async () => {
}
};

export const getAllActiveGrants = async () => {
try {
const grantsSnapshot = await grantsCollection.where("status", "==", PROPOSAL_STATUS.APPROVED).get();
const grants: GrantData[] = [];
grantsSnapshot.forEach(doc => {
grants.push({ id: doc.id, ...doc.data() } as GrantData);
});
return grants;
} catch (error) {
console.error("Error getting all active grants:", error);
throw error;
}
};

export const reviewGrant = async (grantId: string, action: ProposalStatusType) => {
try {
const validActions = Object.values(PROPOSAL_STATUS);
Expand Down
22 changes: 22 additions & 0 deletions packages/nextjs/utils/grants.ts
carletex marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,25 @@ export const PROPOSAL_STATUS = {
} as const;

export type ProposalStatusType = (typeof PROPOSAL_STATUS)[keyof typeof PROPOSAL_STATUS];

export function formatDateFromNow(input: string | number | Date) {
const date = input instanceof Date ? input : new Date(input);
const formatter = new Intl.RelativeTimeFormat("en");
const ranges = [
["years", 3600 * 24 * 365],
["months", 3600 * 24 * 30],
["weeks", 3600 * 24 * 7],
["days", 3600 * 24],
["hours", 3600],
["minutes", 60],
["seconds", 1],
] as const;
const secondsElapsed = (date.getTime() - Date.now()) / 1000;

for (const [rangeType, rangeVal] of ranges) {
if (rangeVal < Math.abs(secondsElapsed)) {
const delta = secondsElapsed / rangeVal;
return formatter.format(Math.round(delta), rangeType);
}
}
}
Loading