mirror of
https://github.com/aljazceru/landscape-template.git
synced 2026-02-01 04:34:38 +01:00
feat: build generic voting api, build useVote hook
This commit is contained in:
@@ -32,7 +32,7 @@ export interface NexusGenInputs {
|
||||
|
||||
export interface NexusGenEnums {
|
||||
POST_TYPE: "Bounty" | "Question" | "Story"
|
||||
VOTE_ITEM_TYPE: "Bounty" | "Comment" | "Project" | "Question" | "Story" | "User"
|
||||
VOTE_ITEM_TYPE: "Bounty" | "PostComment" | "Project" | "Question" | "Story" | "User"
|
||||
}
|
||||
|
||||
export interface NexusGenScalars {
|
||||
@@ -137,13 +137,6 @@ export interface NexusGenObjects {
|
||||
name: string; // String!
|
||||
}
|
||||
Vote: { // root type
|
||||
amount_in_sat: number; // Int!
|
||||
id: number; // Int!
|
||||
paid: boolean; // Boolean!
|
||||
payment_hash: string; // String!
|
||||
payment_request: string; // String!
|
||||
}
|
||||
Vote2: { // root type
|
||||
amount_in_sat: number; // Int!
|
||||
id: number; // Int!
|
||||
item_id: number; // Int!
|
||||
@@ -214,7 +207,6 @@ export interface NexusGenFieldTypes {
|
||||
Mutation: { // field return type
|
||||
confirmVote: NexusGenRootTypes['Vote']; // Vote!
|
||||
vote: NexusGenRootTypes['Vote']; // Vote!
|
||||
vote2: NexusGenRootTypes['Vote2']; // Vote2!
|
||||
}
|
||||
PostComment: { // field return type
|
||||
author: NexusGenRootTypes['User']; // User!
|
||||
@@ -298,14 +290,6 @@ export interface NexusGenFieldTypes {
|
||||
name: string; // String!
|
||||
}
|
||||
Vote: { // field return type
|
||||
amount_in_sat: number; // Int!
|
||||
id: number; // Int!
|
||||
paid: boolean; // Boolean!
|
||||
payment_hash: string; // String!
|
||||
payment_request: string; // String!
|
||||
project: NexusGenRootTypes['Project']; // Project!
|
||||
}
|
||||
Vote2: { // field return type
|
||||
amount_in_sat: number; // Int!
|
||||
id: number; // Int!
|
||||
item_id: number; // Int!
|
||||
@@ -372,7 +356,6 @@ export interface NexusGenFieldTypeNames {
|
||||
Mutation: { // field return type name
|
||||
confirmVote: 'Vote'
|
||||
vote: 'Vote'
|
||||
vote2: 'Vote2'
|
||||
}
|
||||
PostComment: { // field return type name
|
||||
author: 'User'
|
||||
@@ -456,14 +439,6 @@ export interface NexusGenFieldTypeNames {
|
||||
name: 'String'
|
||||
}
|
||||
Vote: { // field return type name
|
||||
amount_in_sat: 'Int'
|
||||
id: 'Int'
|
||||
paid: 'Boolean'
|
||||
payment_hash: 'String'
|
||||
payment_request: 'String'
|
||||
project: 'Project'
|
||||
}
|
||||
Vote2: { // field return type name
|
||||
amount_in_sat: 'Int'
|
||||
id: 'Int'
|
||||
item_id: 'Int'
|
||||
@@ -489,10 +464,6 @@ export interface NexusGenArgTypes {
|
||||
preimage: string; // String!
|
||||
}
|
||||
vote: { // args
|
||||
amount_in_sat: number; // Int!
|
||||
project_id: number; // Int!
|
||||
}
|
||||
vote2: { // args
|
||||
amount_in_sat: number; // Int!
|
||||
item_id: number; // Int!
|
||||
item_type: NexusGenEnums['VOTE_ITEM_TYPE']; // VOTE_ITEM_TYPE!
|
||||
|
||||
@@ -56,8 +56,7 @@ type LnurlDetails {
|
||||
|
||||
type Mutation {
|
||||
confirmVote(payment_request: String!, preimage: String!): Vote!
|
||||
vote(amount_in_sat: Int!, project_id: Int!): Vote!
|
||||
vote2(amount_in_sat: Int!, item_id: Int!, item_type: VOTE_ITEM_TYPE!): Vote2!
|
||||
vote(amount_in_sat: Int!, item_id: Int!, item_type: VOTE_ITEM_TYPE!): Vote!
|
||||
}
|
||||
|
||||
enum POST_TYPE {
|
||||
@@ -168,7 +167,7 @@ type User {
|
||||
|
||||
enum VOTE_ITEM_TYPE {
|
||||
Bounty
|
||||
Comment
|
||||
PostComment
|
||||
Project
|
||||
Question
|
||||
Story
|
||||
@@ -176,15 +175,6 @@ enum VOTE_ITEM_TYPE {
|
||||
}
|
||||
|
||||
type Vote {
|
||||
amount_in_sat: Int!
|
||||
id: Int!
|
||||
paid: Boolean!
|
||||
payment_hash: String!
|
||||
payment_request: String!
|
||||
project: Project!
|
||||
}
|
||||
|
||||
type Vote2 {
|
||||
amount_in_sat: Int!
|
||||
id: Int!
|
||||
item_id: Int!
|
||||
|
||||
@@ -34,7 +34,8 @@ async function getLnurlCallbackUrl(lightning_address) {
|
||||
);
|
||||
}
|
||||
|
||||
async function getPaymetRequestForProject(project, amount_in_sat) {
|
||||
|
||||
async function getPaymetRequestForItem(lightning_address, amount_in_sat) {
|
||||
// # NOTE: CACHING LNURL CALLBACK URLS + PARAMETERS
|
||||
// LNURL flows have a lot of back and forth and can impact
|
||||
// the load time for your application users.
|
||||
@@ -45,11 +46,9 @@ async function getPaymetRequestForProject(project, amount_in_sat) {
|
||||
// careful when trying to optimise the amount of
|
||||
// requests so be mindful of this when you are storing
|
||||
// these items.
|
||||
let lnurlCallbackUrl = project.lnurl_callback_url;
|
||||
|
||||
const amount = amount_in_sat * 1000; // msats
|
||||
if (!lnurlCallbackUrl) {
|
||||
lnurlCallbackUrl = await getLnurlCallbackUrl(project.lightning_address);
|
||||
}
|
||||
let lnurlCallbackUrl = await getLnurlCallbackUrl(lightning_address);
|
||||
return axios
|
||||
.get(lnurlCallbackUrl, { params: { amount } })
|
||||
.then((prResponse) => {
|
||||
@@ -69,10 +68,9 @@ const paginationArgs = (args) => {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getPaymetRequestForProject,
|
||||
getPaymetRequestForItem,
|
||||
hexToUint8Array,
|
||||
lightningAddressToLnurl,
|
||||
getLnurlDetails,
|
||||
|
||||
paginationArgs
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ const {
|
||||
enumType,
|
||||
} = require('nexus')
|
||||
const { parsePaymentRequest } = require('invoices');
|
||||
const { getPaymetRequestForProject, hexToUint8Array } = require('./helpers');
|
||||
const { getPaymetRequestForItem, hexToUint8Array } = require('./helpers');
|
||||
const { createHash } = require('crypto');
|
||||
const { prisma } = require('../prisma')
|
||||
|
||||
@@ -16,9 +16,10 @@ const { prisma } = require('../prisma')
|
||||
// the types of items we can vote to
|
||||
const VOTE_ITEM_TYPE = enumType({
|
||||
name: 'VOTE_ITEM_TYPE',
|
||||
members: ['Story', 'Bounty', 'Question', 'Project', 'User', 'Comment'],
|
||||
members: ['Story', 'Bounty', 'Question', 'Project', 'User', 'PostComment'],
|
||||
})
|
||||
|
||||
|
||||
const Vote = objectType({
|
||||
name: 'Vote',
|
||||
definition(t) {
|
||||
@@ -28,26 +29,6 @@ const Vote = objectType({
|
||||
t.nonNull.string('payment_hash');
|
||||
t.nonNull.boolean('paid');
|
||||
|
||||
t.nonNull.field('project', {
|
||||
type: "Project",
|
||||
resolve: (parent, args,) => {
|
||||
return parent.project ?? prisma.vote.findUnique({
|
||||
where: { id: parent.id }
|
||||
}).project()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const Vote2 = objectType({
|
||||
name: 'Vote2',
|
||||
definition(t) {
|
||||
t.nonNull.int('id');
|
||||
t.nonNull.int('amount_in_sat');
|
||||
t.nonNull.string('payment_request');
|
||||
t.nonNull.string('payment_hash');
|
||||
t.nonNull.boolean('paid');
|
||||
|
||||
t.nonNull.field('item_type', {
|
||||
type: "VOTE_ITEM_TYPE"
|
||||
})
|
||||
@@ -67,46 +48,78 @@ const LnurlDetails = objectType({
|
||||
}
|
||||
})
|
||||
|
||||
// This is the old voting mutation, it can only vote for projects (SHOULD BE REPLACED BY THE NEW VOTE MUTATION WHEN THAT ONE IS WORKING)
|
||||
|
||||
|
||||
|
||||
const getModalOfType = (type) => {
|
||||
switch (type) {
|
||||
case "Story":
|
||||
return prisma.story;
|
||||
case "Question":
|
||||
return prisma.question;
|
||||
case "Project":
|
||||
return prisma.project;
|
||||
case "Comment":
|
||||
return prisma.postComment;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const getLightningAddress = async (item_id, item_type) => {
|
||||
switch (item_type) {
|
||||
case "Story":
|
||||
return prisma.story.findUnique({
|
||||
where: { id: item_id }, include: {
|
||||
user: {
|
||||
select: {
|
||||
lightning_address: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}).then(data => data.user.lightning_address);
|
||||
case "Question":
|
||||
return prisma.question.findUnique({
|
||||
where: { id: item_id }, include: {
|
||||
user: {
|
||||
select: {
|
||||
lightning_address: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}).then(data => data.user.lightning_address);
|
||||
case "Project":
|
||||
return prisma.project.findUnique({
|
||||
where: { id: item_id },
|
||||
select: {
|
||||
lightning_address: true
|
||||
}
|
||||
}).then(data => data.lightning_address);
|
||||
case "Comment":
|
||||
return prisma.postComment.findUnique({
|
||||
where: { id: item_id }, include: {
|
||||
user: {
|
||||
select: {
|
||||
lightning_address: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}).then(data => data.user.lightning_address);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// type => modal
|
||||
// type => lightning address (pr)
|
||||
|
||||
|
||||
// This is the new voting mutation, it can vote for any type of item that we define in the VOTE_ITEM_TYPE enum
|
||||
const voteMutation = extendType({
|
||||
type: "Mutation",
|
||||
definition(t) {
|
||||
t.nonNull.field('vote', {
|
||||
type: "Vote",
|
||||
args: {
|
||||
project_id: nonNull(intArg()),
|
||||
amount_in_sat: nonNull(intArg())
|
||||
},
|
||||
resolve: async (_, args) => {
|
||||
const project = await prisma.project.findUnique({
|
||||
where: { id: args.project_id },
|
||||
});
|
||||
const pr = await getPaymetRequestForProject(project, args.amount_in_sat);
|
||||
const invoice = parsePaymentRequest({ request: pr });
|
||||
return prisma.vote.create({
|
||||
data: {
|
||||
project_id: project.id,
|
||||
amount_in_sat: args.amount_in_sat,
|
||||
payment_request: pr,
|
||||
payment_hash: invoice.id,
|
||||
},
|
||||
include: {
|
||||
project: true
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
// This is the new voting mutation, it can vote for any type of item that we define in the VOTE_ITEM_TYPE enum
|
||||
const vote2Mutation = extendType({
|
||||
type: "Mutation",
|
||||
definition(t) {
|
||||
t.nonNull.field('vote2', {
|
||||
type: "Vote2",
|
||||
args: {
|
||||
item_type: arg({
|
||||
type: nonNull("VOTE_ITEM_TYPE")
|
||||
@@ -117,20 +130,23 @@ const vote2Mutation = extendType({
|
||||
resolve: async (_, args) => {
|
||||
|
||||
const { item_id, item_type, amount_in_sat } = args;
|
||||
const lightning_address = getLightningAddress(item_id, item_type)
|
||||
const pr = await getPaymetRequestForItem(lightning_address, args.amount_in_sat);
|
||||
const invoice = parsePaymentRequest({ request: pr });
|
||||
|
||||
// Create the invoice here according to it's type & get a payment request and a payment hash
|
||||
// #TODO remove votes rows that get added but not confirmed after some time
|
||||
// maybe using a scheduler, timeout, or whatever mean available
|
||||
|
||||
return {
|
||||
id: 111,
|
||||
amount_in_sat: amount_in_sat,
|
||||
payment_request: '{{payment_request}}',
|
||||
payment_hash: '{{payment_hash}}',
|
||||
paid: true,
|
||||
item_type: item_type,
|
||||
item_id: item_id,
|
||||
}
|
||||
return prisma.vote.create({
|
||||
data: {
|
||||
item_type: item_type,
|
||||
item_id: item_id,
|
||||
amount_in_sat: amount_in_sat,
|
||||
payment_request: pr,
|
||||
payment_hash: invoice.id,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -156,17 +172,19 @@ const confirmVoteMutation = extendType({
|
||||
payment_hash: paymentHash,
|
||||
},
|
||||
});
|
||||
|
||||
// if we find a vote it means the preimage is correct and we update the vote and mark it as paid
|
||||
// can we write this nicer?
|
||||
if (vote) {
|
||||
const project = await prisma.project.findUnique({
|
||||
where: { id: vote.project_id },
|
||||
const modal = getModalOfType(vote.item_type);
|
||||
const item = await modal.findUnique({
|
||||
where: { id: vote.item_id },
|
||||
});
|
||||
// count up votes cache
|
||||
await prisma.project.update({
|
||||
where: { id: project.id },
|
||||
await modal.update({
|
||||
where: { id: item.id },
|
||||
data: {
|
||||
votes_count: project.votes_count + vote.amount_in_sat,
|
||||
votes_count: item.votes_count + vote.amount_in_sat,
|
||||
},
|
||||
});
|
||||
// return the current vote
|
||||
@@ -175,9 +193,6 @@ const confirmVoteMutation = extendType({
|
||||
data: {
|
||||
paid: true,
|
||||
preimage: args.preimage,
|
||||
},
|
||||
include: {
|
||||
project: true
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -194,11 +209,9 @@ module.exports = {
|
||||
|
||||
// Types
|
||||
Vote,
|
||||
Vote2,
|
||||
LnurlDetails,
|
||||
|
||||
// Mutations
|
||||
voteMutation,
|
||||
vote2Mutation,
|
||||
confirmVoteMutation
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `project_id` on the `Vote` table. All the data in the column will be lost.
|
||||
- Added the required column `item_id` to the `Vote` table without a default value. This is not possible if the table is not empty.
|
||||
- Added the required column `item_type` to the `Vote` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Vote" DROP CONSTRAINT "Vote_project_id_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Vote" DROP COLUMN "project_id",
|
||||
ADD COLUMN "item_id" INTEGER NOT NULL,
|
||||
ADD COLUMN "item_type" TEXT NOT NULL;
|
||||
@@ -22,8 +22,8 @@ model Tag {
|
||||
|
||||
model Vote {
|
||||
id Int @id @default(autoincrement())
|
||||
project Project @relation(fields: [project_id], references: [id])
|
||||
project_id Int
|
||||
item_id Int
|
||||
item_type String
|
||||
amount_in_sat Int
|
||||
payment_request String?
|
||||
payment_hash String?
|
||||
@@ -73,7 +73,6 @@ model Project {
|
||||
category Category @relation(fields: [category_id], references: [id])
|
||||
category_id Int
|
||||
votes_count Int @default(0)
|
||||
vote Vote[]
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
awards Award[]
|
||||
|
||||
@@ -3,11 +3,10 @@ import React, { FormEvent, useState } from 'react';
|
||||
import { AiFillThunderbolt } from 'react-icons/ai'
|
||||
import { IoClose } from 'react-icons/io5'
|
||||
import { ModalCard, modalCardVariants } from 'src/Components/Modals/ModalsContainer/ModalsContainer';
|
||||
import { useAppSelector } from 'src/utils/hooks';
|
||||
import { PaymentStatus, useVote } from 'src/utils/hooks';
|
||||
import Confetti from "react-confetti";
|
||||
import { Wallet_Service } from 'src/services';
|
||||
import { useWindowSize } from '@react-hookz/web';
|
||||
import { useConfirmVoteMutation, useVoteMutation } from 'src/graphql';
|
||||
import { Vote_Item_Type } from 'src/graphql';
|
||||
|
||||
const defaultOptions = [
|
||||
{ text: '100 sat', value: 100 },
|
||||
@@ -16,17 +15,6 @@ const defaultOptions = [
|
||||
]
|
||||
|
||||
|
||||
enum PaymentStatus {
|
||||
DEFAULT,
|
||||
FETCHING_PAYMENT_DETAILS,
|
||||
PAID,
|
||||
AWAITING_PAYMENT,
|
||||
PAYMENT_CONFIRMED,
|
||||
NOT_PAID,
|
||||
CANCELED
|
||||
}
|
||||
|
||||
|
||||
interface Props extends ModalCard {
|
||||
projectId: number;
|
||||
initVotes?: number;
|
||||
@@ -35,57 +23,24 @@ interface Props extends ModalCard {
|
||||
export default function VoteCard({ onClose, direction, projectId, initVotes, ...props }: Props) {
|
||||
const { width, height } = useWindowSize()
|
||||
|
||||
const { isWalletConnected } = useAppSelector(state => ({
|
||||
isWalletConnected: state.wallet.isConnected,
|
||||
initVotes: state.vote.voteAmount,
|
||||
projectId: state.project.openId
|
||||
}));
|
||||
|
||||
|
||||
const [selectedOption, setSelectedOption] = useState(10);
|
||||
const [voteAmount, setVoteAmount] = useState<number>(initVotes ?? 10);
|
||||
const [paymentStatus, setPaymentStatus] = useState<PaymentStatus>(PaymentStatus.DEFAULT);
|
||||
|
||||
const [vote, { data }] = useVoteMutation({
|
||||
onCompleted: async (votingData) => {
|
||||
try {
|
||||
setPaymentStatus(PaymentStatus.AWAITING_PAYMENT);
|
||||
const webln = await Wallet_Service.getWebln()
|
||||
const paymentResponse = await webln.sendPayment(votingData.vote.payment_request);
|
||||
setPaymentStatus(PaymentStatus.PAID);
|
||||
confirmVote({
|
||||
variables: {
|
||||
paymentRequest: votingData.vote.payment_request,
|
||||
preimage: paymentResponse.preimage
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
setPaymentStatus(PaymentStatus.NOT_PAID);
|
||||
}
|
||||
|
||||
const { vote, paymentStatus } = useVote({
|
||||
onSuccess: () => {
|
||||
setTimeout(() => {
|
||||
onClose?.();
|
||||
}, 4000);
|
||||
},
|
||||
onError: (error) => {
|
||||
console.log(error);
|
||||
alert("Something wrong happened...")
|
||||
setPaymentStatus(PaymentStatus.NOT_PAID);
|
||||
onError: () => {
|
||||
setTimeout(() => {
|
||||
onClose?.();
|
||||
}, 4000);
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
const [confirmVote, { data: confirmedVoteData }] = useConfirmVoteMutation({
|
||||
onCompleted: (votingData) => {
|
||||
setPaymentStatus(PaymentStatus.PAYMENT_CONFIRMED);
|
||||
setTimeout(() => {
|
||||
onClose?.();
|
||||
}, 4000);
|
||||
},
|
||||
|
||||
onError: () => { }
|
||||
|
||||
});
|
||||
|
||||
const onChangeInput = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setSelectedOption(-1);
|
||||
@@ -99,8 +54,7 @@ export default function VoteCard({ onClose, direction, projectId, initVotes, ...
|
||||
|
||||
const requestPayment = (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
setPaymentStatus(PaymentStatus.FETCHING_PAYMENT_DETAILS);
|
||||
vote({ variables: { "amountInSat": voteAmount, "projectId": projectId! } });
|
||||
vote({ variables: { "amountInSat": voteAmount, "itemId": projectId!, itemType: Vote_Item_Type.Project } });
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -75,7 +75,6 @@ export type Mutation = {
|
||||
__typename?: 'Mutation';
|
||||
confirmVote: Vote;
|
||||
vote: Vote;
|
||||
vote2: Vote2;
|
||||
};
|
||||
|
||||
|
||||
@@ -86,12 +85,6 @@ export type MutationConfirmVoteArgs = {
|
||||
|
||||
|
||||
export type MutationVoteArgs = {
|
||||
amount_in_sat: Scalars['Int'];
|
||||
project_id: Scalars['Int'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationVote2Args = {
|
||||
amount_in_sat: Scalars['Int'];
|
||||
item_id: Scalars['Int'];
|
||||
item_type: Vote_Item_Type;
|
||||
@@ -274,7 +267,7 @@ export type User = {
|
||||
|
||||
export enum Vote_Item_Type {
|
||||
Bounty = 'Bounty',
|
||||
Comment = 'Comment',
|
||||
PostComment = 'PostComment',
|
||||
Project = 'Project',
|
||||
Question = 'Question',
|
||||
Story = 'Story',
|
||||
@@ -285,16 +278,6 @@ export type Vote = {
|
||||
__typename?: 'Vote';
|
||||
amount_in_sat: Scalars['Int'];
|
||||
id: Scalars['Int'];
|
||||
paid: Scalars['Boolean'];
|
||||
payment_hash: Scalars['String'];
|
||||
payment_request: Scalars['String'];
|
||||
project: Project;
|
||||
};
|
||||
|
||||
export type Vote2 = {
|
||||
__typename?: 'Vote2';
|
||||
amount_in_sat: Scalars['Int'];
|
||||
id: Scalars['Int'];
|
||||
item_id: Scalars['Int'];
|
||||
item_type: Vote_Item_Type;
|
||||
paid: Scalars['Boolean'];
|
||||
@@ -372,12 +355,13 @@ export type ProjectDetailsQueryVariables = Exact<{
|
||||
export type ProjectDetailsQuery = { __typename?: 'Query', getProject: { __typename?: 'Project', id: number, title: string, description: string, cover_image: string, thumbnail_image: string, screenshots: Array<string>, website: string, lightning_address: string | null, lnurl_callback_url: string | null, votes_count: number, category: { __typename?: 'Category', id: number, title: string }, awards: Array<{ __typename?: 'Award', title: string, image: string, url: string, id: number }>, tags: Array<{ __typename?: 'Tag', id: number, title: string }> } };
|
||||
|
||||
export type VoteMutationVariables = Exact<{
|
||||
projectId: Scalars['Int'];
|
||||
itemType: Vote_Item_Type;
|
||||
itemId: Scalars['Int'];
|
||||
amountInSat: Scalars['Int'];
|
||||
}>;
|
||||
|
||||
|
||||
export type VoteMutation = { __typename?: 'Mutation', vote: { __typename?: 'Vote', id: number, amount_in_sat: number, payment_request: string, payment_hash: string, paid: boolean } };
|
||||
export type VoteMutation = { __typename?: 'Mutation', vote: { __typename?: 'Vote', id: number, amount_in_sat: number, payment_request: string, payment_hash: string, paid: boolean, item_type: Vote_Item_Type, item_id: number } };
|
||||
|
||||
export type ConfirmVoteMutationVariables = Exact<{
|
||||
paymentRequest: Scalars['String'];
|
||||
@@ -385,7 +369,7 @@ export type ConfirmVoteMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type ConfirmVoteMutation = { __typename?: 'Mutation', confirmVote: { __typename?: 'Vote', id: number, amount_in_sat: number, payment_request: string, payment_hash: string, paid: boolean, project: { __typename?: 'Project', id: number, votes_count: number } } };
|
||||
export type ConfirmVoteMutation = { __typename?: 'Mutation', confirmVote: { __typename?: 'Vote', id: number, amount_in_sat: number, payment_request: string, payment_hash: string, paid: boolean, item_type: Vote_Item_Type, item_id: number } };
|
||||
|
||||
|
||||
export const NavCategoriesDocument = gql`
|
||||
@@ -1029,13 +1013,15 @@ export type ProjectDetailsQueryHookResult = ReturnType<typeof useProjectDetailsQ
|
||||
export type ProjectDetailsLazyQueryHookResult = ReturnType<typeof useProjectDetailsLazyQuery>;
|
||||
export type ProjectDetailsQueryResult = Apollo.QueryResult<ProjectDetailsQuery, ProjectDetailsQueryVariables>;
|
||||
export const VoteDocument = gql`
|
||||
mutation Vote($projectId: Int!, $amountInSat: Int!) {
|
||||
vote(project_id: $projectId, amount_in_sat: $amountInSat) {
|
||||
mutation Vote($itemType: VOTE_ITEM_TYPE!, $itemId: Int!, $amountInSat: Int!) {
|
||||
vote(item_type: $itemType, item_id: $itemId, amount_in_sat: $amountInSat) {
|
||||
id
|
||||
amount_in_sat
|
||||
payment_request
|
||||
payment_hash
|
||||
paid
|
||||
item_type
|
||||
item_id
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -1054,7 +1040,8 @@ export type VoteMutationFn = Apollo.MutationFunction<VoteMutation, VoteMutationV
|
||||
* @example
|
||||
* const [voteMutation, { data, loading, error }] = useVoteMutation({
|
||||
* variables: {
|
||||
* projectId: // value for 'projectId'
|
||||
* itemType: // value for 'itemType'
|
||||
* itemId: // value for 'itemId'
|
||||
* amountInSat: // value for 'amountInSat'
|
||||
* },
|
||||
* });
|
||||
@@ -1074,10 +1061,8 @@ export const ConfirmVoteDocument = gql`
|
||||
payment_request
|
||||
payment_hash
|
||||
paid
|
||||
project {
|
||||
id
|
||||
votes_count
|
||||
}
|
||||
item_type
|
||||
item_id
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -5,3 +5,4 @@ export * from "./useInfiniteQuery";
|
||||
export * from "./useReachedBottom";
|
||||
export * from "./useAutoResizableTextArea";
|
||||
export * from "./useCopyToClipboard";
|
||||
export * from "./useVote";
|
||||
|
||||
1
src/utils/hooks/useVote/index.ts
Normal file
1
src/utils/hooks/useVote/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './useVote'
|
||||
96
src/utils/hooks/useVote/useVote.tsx
Normal file
96
src/utils/hooks/useVote/useVote.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
import { gql } from '@apollo/client';
|
||||
import { useState } from 'react';
|
||||
import { useConfirmVoteMutation, useVoteMutation } from 'src/graphql';
|
||||
import { Wallet_Service } from 'src/services';
|
||||
|
||||
export enum PaymentStatus {
|
||||
DEFAULT,
|
||||
FETCHING_PAYMENT_DETAILS,
|
||||
PAID,
|
||||
AWAITING_PAYMENT,
|
||||
PAYMENT_CONFIRMED,
|
||||
NOT_PAID,
|
||||
CANCELED
|
||||
}
|
||||
|
||||
|
||||
export const useVote = ({ onSuccess, onError }: {
|
||||
onSuccess?: () => void
|
||||
onError?: (error: any) => void
|
||||
}) => {
|
||||
|
||||
const [paymentStatus, setPaymentStatus] = useState<PaymentStatus>(PaymentStatus.DEFAULT);
|
||||
|
||||
const [voteMutaion] = useVoteMutation({
|
||||
onCompleted: async (votingData) => {
|
||||
try {
|
||||
setPaymentStatus(PaymentStatus.AWAITING_PAYMENT);
|
||||
const webln = await Wallet_Service.getWebln()
|
||||
const paymentResponse = await webln.sendPayment(votingData.vote.payment_request);
|
||||
setPaymentStatus(PaymentStatus.PAID);
|
||||
confirmVote({
|
||||
variables: {
|
||||
paymentRequest: votingData.vote.payment_request,
|
||||
preimage: paymentResponse.preimage
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
setPaymentStatus(PaymentStatus.NOT_PAID);
|
||||
}
|
||||
|
||||
},
|
||||
onError: (error) => {
|
||||
console.log(error);
|
||||
alert("Something wrong happened...")
|
||||
setPaymentStatus(PaymentStatus.NOT_PAID);
|
||||
onError?.(error)
|
||||
}
|
||||
});
|
||||
|
||||
const [confirmVote] = useConfirmVoteMutation({
|
||||
onCompleted: () => {
|
||||
setPaymentStatus(PaymentStatus.PAYMENT_CONFIRMED);
|
||||
onSuccess?.();
|
||||
},
|
||||
update(cache, { data }) {
|
||||
try {
|
||||
const { item_id, item_type, amount_in_sat } = data!.confirmVote;
|
||||
const { votes_count } = cache.readFragment({
|
||||
id: `${item_type}:${item_id}`,
|
||||
fragment: gql`
|
||||
fragment My${item_type} on ${item_type} {
|
||||
votes_count
|
||||
}`
|
||||
}) ?? {};
|
||||
cache.writeFragment({
|
||||
id: `${item_type}:${item_id}`,
|
||||
fragment: gql`
|
||||
fragment My${item_type} on ${item_type} {
|
||||
votes_count
|
||||
}
|
||||
`,
|
||||
data: {
|
||||
votes_count: votes_count + amount_in_sat
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
onError: () => { }
|
||||
|
||||
});
|
||||
|
||||
|
||||
const vote = (...params: Parameters<typeof voteMutaion>) => {
|
||||
setPaymentStatus(PaymentStatus.FETCHING_PAYMENT_DETAILS)
|
||||
voteMutaion(...params)
|
||||
}
|
||||
return {
|
||||
paymentStatus,
|
||||
vote
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
mutation Vote($projectId: Int!, $amountInSat: Int!) {
|
||||
vote(project_id: $projectId, amount_in_sat: $amountInSat) {
|
||||
mutation Vote($itemType: VOTE_ITEM_TYPE!, $itemId: Int!, $amountInSat: Int!) {
|
||||
vote(item_type: $itemType, item_id: $itemId, amount_in_sat: $amountInSat) {
|
||||
id
|
||||
amount_in_sat
|
||||
payment_request
|
||||
payment_hash
|
||||
paid
|
||||
item_type
|
||||
item_id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +17,7 @@ mutation ConfirmVote($paymentRequest: String!, $preimage: String!) {
|
||||
payment_request
|
||||
payment_hash
|
||||
paid
|
||||
project {
|
||||
id
|
||||
votes_count
|
||||
}
|
||||
item_type
|
||||
item_id
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user