feat: connect donation sats api, build donation sat skeleton, build donation sats mock api

This commit is contained in:
MTG2000
2022-05-25 15:47:58 +03:00
parent f1f0be7f79
commit f56e269148
15 changed files with 192 additions and 65 deletions

View File

@@ -85,10 +85,10 @@ export interface NexusGenObjects {
payment_request: string; // String!
}
DonationsStats: { // root type
applications: number; // Int!
donations: number; // Int!
prizes: number; // Int!
touranments: number; // Int!
applications: string; // String!
donations: string; // String!
prizes: string; // String!
touranments: string; // String!
}
Hackathon: { // root type
cover_image: string; // String!
@@ -232,10 +232,10 @@ export interface NexusGenFieldTypes {
payment_request: string; // String!
}
DonationsStats: { // field return type
applications: number; // Int!
donations: number; // Int!
prizes: number; // Int!
touranments: number; // Int!
applications: string; // String!
donations: string; // String!
prizes: string; // String!
touranments: string; // String!
}
Hackathon: { // field return type
cover_image: string; // String!
@@ -289,7 +289,7 @@ export interface NexusGenFieldTypes {
allTopics: NexusGenRootTypes['Topic'][]; // [Topic!]!
getAllHackathons: NexusGenRootTypes['Hackathon'][]; // [Hackathon!]!
getCategory: NexusGenRootTypes['Category']; // Category!
getDonationsStats: NexusGenRootTypes['DonationsStats'][]; // [DonationsStats!]!
getDonationsStats: NexusGenRootTypes['DonationsStats']; // DonationsStats!
getFeed: NexusGenRootTypes['Post'][]; // [Post!]!
getLnurlDetailsForProject: NexusGenRootTypes['LnurlDetails']; // LnurlDetails!
getPostById: NexusGenRootTypes['Post']; // Post!
@@ -411,10 +411,10 @@ export interface NexusGenFieldTypeNames {
payment_request: 'String'
}
DonationsStats: { // field return type name
applications: 'Int'
donations: 'Int'
prizes: 'Int'
touranments: 'Int'
applications: 'String'
donations: 'String'
prizes: 'String'
touranments: 'String'
}
Hackathon: { // field return type name
cover_image: 'String'

View File

@@ -58,10 +58,10 @@ type Donation {
}
type DonationsStats {
applications: Int!
donations: Int!
prizes: Int!
touranments: Int!
applications: String!
donations: String!
prizes: String!
touranments: String!
}
type Hackathon {
@@ -138,7 +138,7 @@ type Query {
allTopics: [Topic!]!
getAllHackathons(sortBy: String, topic: Int): [Hackathon!]!
getCategory(id: Int!): Category!
getDonationsStats: [DonationsStats!]!
getDonationsStats: DonationsStats!
getFeed(skip: Int = 0, sortBy: String = "all", take: Int = 10, topic: Int = 0): [Post!]!
getLnurlDetailsForProject(project_id: Int!): LnurlDetails!
getPostById(id: Int!, type: POST_TYPE!): Post!

View File

@@ -106,31 +106,36 @@ const confirmDonateMutation = extendType({
const DonationsStats = objectType({
name: 'DonationsStats',
definition(t) {
t.nonNull.int("prizes");
t.nonNull.int("touranments");
t.nonNull.int("donations");
t.nonNull.int("applications");
t.nonNull.string("prizes");
t.nonNull.string("touranments");
t.nonNull.string("donations");
t.nonNull.string("applications");
},
})
const getDonationsStats = extendType({
type: "Query",
definition(t) {
t.nonNull.list.nonNull.field('getDonationsStats', {
t.nonNull.field('getDonationsStats', {
type: "DonationsStats",
resolve() {
return {
prizes: 2600,
touranments: 2,
donations: prisma.donation.aggregate({
async resolve() {
const [donations, applications] = await Promise.all([
prisma.donation.aggregate({
_sum: {
amount: true
},
where: {
paid: true
}
}),
applications: prisma.project.count()
}).then(d => d._sum.amount),
prisma.project.count()]);
// #TODO add a measurement unit for prizes & donations (eg. $ or sats or BTC)
return {
prizes: 2600,
touranments: 2,
donations,
applications
}
}
})

View File

@@ -57,7 +57,7 @@ export default function DonateCard() {
<form onSubmit={requestPayment} className="mt-32 ">
<div className="input-wrapper">
<input
className={` input-text input-removed-arrows`}
className={`input-text input-removed-arrows`}
value={donationAmount} onChange={onChangeInput}
type="number"
placeholder="1,000"

View File

@@ -18,7 +18,7 @@ export default function DonatePage() {
items={[
{
heading: "How are donations spent?",
content: <p className="whitespace-pre-line">
content: <p className=" whitespace-pre-line">
Shock the Web is a virtual hackathon to promote, explore, build and design web applications that can interact with WebLN enabled wallets and browsers. We want to make building on bitcoin more accessible to the masses of web developers out there.
<br />
Bitcoin development can seem scary for new developers coming in, but it doesn't have to be. With the lightning network's toolkit and libraries a bunch of new opportunities are waiting to be explored. We hope these hackathons can be a chance for you to preview what is possible on bitcoin and the lightning network by fostering collaboration, hopefully shortening (or easing) any developer onboarding time, and helping you connect with other bitcoiners in a fun and friendly space.
@@ -26,7 +26,7 @@ export default function DonatePage() {
},
{
heading: "Who is working on BOLT🔩FUN?",
content: <p className="whitespace-pre-line">
content: <p className=" whitespace-pre-line">
Shock the Web is a virtual hackathon to promote, explore, build and design web applications that can interact with WebLN enabled wallets and browsers. We want to make building on bitcoin more accessible to the masses of web developers out there.
<br />
Bitcoin development can seem scary for new developers coming in, but it doesn't have to be. With the lightning network's toolkit and libraries a bunch of new opportunities are waiting to be explored. We hope these hackathons can be a chance for you to preview what is possible on bitcoin and the lightning network by fostering collaboration, hopefully shortening (or easing) any developer onboarding time, and helping you connect with other bitcoiners in a fun and friendly space.
@@ -34,7 +34,7 @@ export default function DonatePage() {
},
{
heading: "How can makers win prizes?",
content: <p className="whitespace-pre-line">
content: <p className=" whitespace-pre-line">
Shock the Web is a virtual hackathon to promote, explore, build and design web applications that can interact with WebLN enabled wallets and browsers. We want to make building on bitcoin more accessible to the masses of web developers out there.
<br />
Bitcoin development can seem scary for new developers coming in, but it doesn't have to be. With the lightning network's toolkit and libraries a bunch of new opportunities are waiting to be explored. We hope these hackathons can be a chance for you to preview what is possible on bitcoin and the lightning network by fostering collaboration, hopefully shortening (or easing) any developer onboarding time, and helping you connect with other bitcoiners in a fun and friendly space.
@@ -42,7 +42,7 @@ export default function DonatePage() {
},
{
heading: "How can I donate?",
content: <p className="whitespace-pre-line">
content: <p className=" whitespace-pre-line">
Shock the Web is a virtual hackathon to promote, explore, build and design web applications that can interact with WebLN enabled wallets and browsers. We want to make building on bitcoin more accessible to the masses of web developers out there.
<br />
Bitcoin development can seem scary for new developers coming in, but it doesn't have to be. With the lightning network's toolkit and libraries a bunch of new opportunities are waiting to be explored. We hope these hackathons can be a chance for you to preview what is possible on bitcoin and the lightning network by fostering collaboration, hopefully shortening (or easing) any developer onboarding time, and helping you connect with other bitcoiners in a fun and friendly space.

View File

@@ -1,32 +1,47 @@
import { BiCoinStack } from "react-icons/bi";
import { FiGrid } from "react-icons/fi";
import { IoMedalOutline, IoRocketOutline } from "react-icons/io5";
import { useDonationsStatsQuery } from "src/graphql";
import { generateList } from "src/utils/helperFunctions";
import StatCard from "../StatCard/StatCard";
import StatCardSkeleton from "../StatCard/StatCard.Skeleton";
export default function DonationStats() {
const donationsStatQuery = useDonationsStatsQuery();
return (
<div className="grid sm:grid-cols-2 md:grid-cols-4 gap-16">
<StatCard
color="#8B5CF6"
label={<><BiCoinStack className='scale-125 mr-8' /> <span className="align-middle">Donations</span></>}
value='$2.6k'
/>
<StatCard
color="#F59E0B"
label={<><IoRocketOutline className='scale-125 mr-8' /> <span className="align-middle">Tournaments</span></>}
value='1'
/>
<StatCard
color="#22C55E"
label={<><IoMedalOutline className='scale-125 mr-8' /> <span className="align-middle">Prizes</span></>}
value='$2.5k'
/>
<StatCard
color="#3B82F6"
label={<><FiGrid className='scale-125 mr-8' /> <span className="align-middle">Applications</span></>}
value='36'
/>
<div className="grid grid-cols-2 md:grid-cols-4 gap-16">
{donationsStatQuery.loading && generateList(<StatCardSkeleton />, 4)}
{!donationsStatQuery.loading &&
<>
<StatCard
color="#8B5CF6"
label={<><BiCoinStack className='w-full lg:w-auto scale-125 mr-8' /> <span className="align-middle">Donations</span></>}
value={donationsStatQuery.data?.getDonationsStats.donations}
/>
<StatCard
color="#F59E0B"
label={<><IoRocketOutline className='w-full lg:w-auto scale-125 mr-8' /> <span className="align-middle">Tournaments</span></>}
value={donationsStatQuery.data?.getDonationsStats.touranments}
/>
<StatCard
color="#22C55E"
label={<><IoMedalOutline className='w-full lg:w-auto scale-125 mr-8' /> <span className="align-middle">Prizes</span></>}
value={donationsStatQuery.data?.getDonationsStats.prizes}
/>
<StatCard
color="#3B82F6"
label={<><FiGrid className='w-full lg:w-auto scale-125 mr-8' /> <span className="align-middle">Applications</span></>}
value={donationsStatQuery.data?.getDonationsStats.applications}
/>
</>
}
</div>
)
}

View File

@@ -0,0 +1,8 @@
query DonationsStats {
getDonationsStats {
prizes
touranments
donations
applications
}
}

View File

@@ -6,7 +6,7 @@ import styles from './styles.module.scss'
export default function Header() {
return (
<div className={`${styles.header}`}>
<div>
<div className='min-w-0'>
<div className="flex items-center gap-24 flex-col md:flex-row">
<div>
<h1 className="text-[54px] font-bolder">

View File

@@ -4,8 +4,10 @@
padding: 56px 0;
min-height: calc(min(1080px, 90vh));
background: #ffecf9;
background: linear-gradient(40deg, white -5%, #ffb7d963 74%, #e3faff61 100%);
background: linear-gradient(40deg, white 7%, #ffdadaa3 62%, #d0f6ff5c 96%);
background-size: 120% 120%;
animation: Animation 3s ease infinite;
display: grid;
grid-template-areas: ". content .";
grid-template-columns: minmax(16px, 1fr) minmax(auto, 910px) minmax(16px, 1fr);
@@ -14,3 +16,15 @@
grid-area: content;
}
}
@keyframes Animation {
0% {
background-position: 0% 20%;
}
50% {
background-position: 20% 0%;
}
100% {
background-position: 0% 20%;
}
}

View File

@@ -0,0 +1,15 @@
import Skeleton from 'react-loading-skeleton'
export default function StatCardSkeleton() {
return (
<div className="bg-white p-24 rounded-16 text-center" >
<p className="text-body4">
<Skeleton width={'10ch'} />
</p>
<p className="text-h2 mt-8">
<Skeleton width={'4ch'} />
</p>
</div>
)
}

View File

@@ -1,6 +1,7 @@
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { FiGrid } from 'react-icons/fi'
import StatCard from './StatCard';
import StatCardSkeleton from './StatCard.Skeleton';
export default {
title: 'Donations/Donate Page/StatCard',
@@ -20,4 +21,9 @@ Default.args = {
value: '36'
}
const LoadingTemplate: ComponentStory<typeof StatCard> = (args) => <div className="max-w-[220px]"><StatCardSkeleton ></StatCardSkeleton></div>
export const Loading = LoadingTemplate.bind({});
Loading.args = {
}

View File

@@ -16,7 +16,7 @@ export default function StatCard(props: Props) {
<p className="text-body4">
{props.label}
</p>
<p className="text-h2 mt-8 font-bolder">
<p className="text-h3 sm:text-h2 mt-8 font-bolder">
{props.value}
</p>
</div>

View File

@@ -76,10 +76,10 @@ export type Donation = {
export type DonationsStats = {
__typename?: 'DonationsStats';
applications: Scalars['Int'];
donations: Scalars['Int'];
prizes: Scalars['Int'];
touranments: Scalars['Int'];
applications: Scalars['String'];
donations: Scalars['String'];
prizes: Scalars['String'];
touranments: Scalars['String'];
};
export type Hackathon = {
@@ -186,7 +186,7 @@ export type Query = {
allTopics: Array<Topic>;
getAllHackathons: Array<Hackathon>;
getCategory: Category;
getDonationsStats: Array<DonationsStats>;
getDonationsStats: DonationsStats;
getFeed: Array<Post>;
getLnurlDetailsForProject: LnurlDetails;
getPostById: Post;
@@ -350,6 +350,11 @@ export type SearchProjectsQueryVariables = Exact<{
export type SearchProjectsQuery = { __typename?: 'Query', searchProjects: Array<{ __typename?: 'Project', id: number, thumbnail_image: string, title: string, category: { __typename?: 'Category', title: string, id: number } }> };
export type DonationsStatsQueryVariables = Exact<{ [key: string]: never; }>;
export type DonationsStatsQuery = { __typename?: 'Query', getDonationsStats: { __typename?: 'DonationsStats', prizes: string, touranments: string, donations: string, applications: string } };
export type DonateMutationVariables = Exact<{
amountInSat: Scalars['Int'];
}>;
@@ -531,6 +536,43 @@ export function useSearchProjectsLazyQuery(baseOptions?: Apollo.LazyQueryHookOpt
export type SearchProjectsQueryHookResult = ReturnType<typeof useSearchProjectsQuery>;
export type SearchProjectsLazyQueryHookResult = ReturnType<typeof useSearchProjectsLazyQuery>;
export type SearchProjectsQueryResult = Apollo.QueryResult<SearchProjectsQuery, SearchProjectsQueryVariables>;
export const DonationsStatsDocument = gql`
query DonationsStats {
getDonationsStats {
prizes
touranments
donations
applications
}
}
`;
/**
* __useDonationsStatsQuery__
*
* To run a query within a React component, call `useDonationsStatsQuery` and pass it any options that fit your needs.
* When your component renders, `useDonationsStatsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useDonationsStatsQuery({
* variables: {
* },
* });
*/
export function useDonationsStatsQuery(baseOptions?: Apollo.QueryHookOptions<DonationsStatsQuery, DonationsStatsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<DonationsStatsQuery, DonationsStatsQueryVariables>(DonationsStatsDocument, options);
}
export function useDonationsStatsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<DonationsStatsQuery, DonationsStatsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<DonationsStatsQuery, DonationsStatsQueryVariables>(DonationsStatsDocument, options);
}
export type DonationsStatsQueryHookResult = ReturnType<typeof useDonationsStatsQuery>;
export type DonationsStatsLazyQueryHookResult = ReturnType<typeof useDonationsStatsLazyQuery>;
export type DonationsStatsQueryResult = Apollo.QueryResult<DonationsStatsQuery, DonationsStatsQueryVariables>;
export const DonateDocument = gql`
mutation Donate($amountInSat: Int!) {
donate(amount_in_sat: $amountInSat) {

View File

@@ -25,6 +25,7 @@ import {
GetHackathonsQueryVariables,
AllTopicsQuery,
AllTopicsQueryVariables,
DonationsStatsQuery,
} from 'src/graphql'
const delay = (ms = 1000) => new Promise((res) => setTimeout(res, ms + Math.random() * 1000))
@@ -172,4 +173,20 @@ export const handlers = [
)
}),
graphql.query<DonationsStatsQuery>('DonationsStats', async (req, res, ctx) => {
await delay()
return res(
ctx.data({
getDonationsStats: {
applications: '32',
donations: "$2.6k",
prizes: "$2.5k",
touranments: "1",
}
})
)
}),
]

View File

@@ -1,4 +1,4 @@
import React, { ComponentProps, ComponentType, Suspense } from "react";
import React, { ComponentProps, ComponentType, ReactNode, Suspense } from "react";
import { RotatingLines } from "react-loader-spinner";
export function random(min: number, max: number) {
@@ -85,3 +85,8 @@ export function shuffle<T>(_array: Array<T>) {
return array;
}
export function generateList(component: React.ReactElement, cnt: number) {
return Array(cnt).fill(0).map((_, idx) => React.cloneElement(component, { key: idx }))
}