invite graphql + basic frontend
This commit is contained in:
parent
09c4883366
commit
4935c7dc1c
|
@ -4,5 +4,6 @@ import item from './item'
|
||||||
import wallet from './wallet'
|
import wallet from './wallet'
|
||||||
import lnurl from './lnurl'
|
import lnurl from './lnurl'
|
||||||
import notifications from './notifications'
|
import notifications from './notifications'
|
||||||
|
import invite from './invite'
|
||||||
|
|
||||||
export default [user, item, message, wallet, lnurl, notifications]
|
export default [user, item, message, wallet, lnurl, notifications, invite]
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { AuthenticationError, UserInputError } from 'apollo-server-micro'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Query: {
|
||||||
|
invites: async (parent, args, { me, models }) => {
|
||||||
|
if (!me) {
|
||||||
|
throw new AuthenticationError('you must be logged in')
|
||||||
|
}
|
||||||
|
|
||||||
|
return await models.invite.findMany({
|
||||||
|
where: {
|
||||||
|
userId: me.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Mutation: {
|
||||||
|
createInvite: async (parent, { gift, limit }, { me, models }) => {
|
||||||
|
if (!me) {
|
||||||
|
throw new AuthenticationError('you must be logged in')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gift || (gift && gift < 0)) {
|
||||||
|
throw new UserInputError('gift must be >= 0', { argumentName: 'gift' })
|
||||||
|
}
|
||||||
|
|
||||||
|
return await models.invite.create({
|
||||||
|
data: { gift, limit, userId: me.id }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
Invite: {
|
||||||
|
invitees: async (invite, args, { models }) => []
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import item from './item'
|
||||||
import wallet from './wallet'
|
import wallet from './wallet'
|
||||||
import lnurl from './lnurl'
|
import lnurl from './lnurl'
|
||||||
import notifications from './notifications'
|
import notifications from './notifications'
|
||||||
|
import invite from './invite'
|
||||||
|
|
||||||
const link = gql`
|
const link = gql`
|
||||||
type Query {
|
type Query {
|
||||||
|
@ -21,4 +22,4 @@ const link = gql`
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export default [link, user, item, message, wallet, lnurl, notifications]
|
export default [link, user, item, message, wallet, lnurl, notifications, invite]
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { gql } from 'apollo-server-micro'
|
||||||
|
|
||||||
|
export default gql`
|
||||||
|
extend type Query {
|
||||||
|
invites: [Invite!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
extend type Mutation {
|
||||||
|
createInvite(gift: Int!, limit: Int): Invite
|
||||||
|
}
|
||||||
|
|
||||||
|
type Invite {
|
||||||
|
id: ID!
|
||||||
|
createdAt: String!
|
||||||
|
invitees: [User!]!
|
||||||
|
gift: Int!
|
||||||
|
limit: Int
|
||||||
|
revoked: Boolean!
|
||||||
|
}
|
||||||
|
`
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { gql } from '@apollo/client'
|
||||||
|
|
||||||
|
export const INVITE_FIELDS = gql`
|
||||||
|
fragment InviteFields on Invite {
|
||||||
|
id
|
||||||
|
createdAt
|
||||||
|
invitees {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
}
|
||||||
|
gift
|
||||||
|
limit
|
||||||
|
revoked
|
||||||
|
}
|
||||||
|
`
|
|
@ -0,0 +1,93 @@
|
||||||
|
import Layout from '../../components/layout'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
import { Form, Input, SubmitButton } from '../../components/form'
|
||||||
|
import { InputGroup } from 'react-bootstrap'
|
||||||
|
import { gql, useMutation, useQuery } from '@apollo/client'
|
||||||
|
import { INVITE_FIELDS } from '../../fragments/invites'
|
||||||
|
|
||||||
|
export const InviteSchema = Yup.object({
|
||||||
|
gift: Yup.number().typeError('must be a number')
|
||||||
|
.min(0, 'must be positive').integer('must be whole').required(),
|
||||||
|
limit: Yup.number().typeError('must be a number')
|
||||||
|
.positive('must be positive').integer('must be whole')
|
||||||
|
})
|
||||||
|
|
||||||
|
function InviteForm () {
|
||||||
|
const [createInvite] = useMutation(
|
||||||
|
gql`
|
||||||
|
${INVITE_FIELDS}
|
||||||
|
mutation createInvite($gift: Int!, $limit: Int) {
|
||||||
|
createInvite(gift: $gift, limit: $limit) {
|
||||||
|
...InviteFields
|
||||||
|
}
|
||||||
|
}`, {
|
||||||
|
update (cache, { data: { createInvite } }) {
|
||||||
|
cache.modify({
|
||||||
|
fields: {
|
||||||
|
invites (existingInviteRefs = []) {
|
||||||
|
const newInviteRef = cache.writeFragment({
|
||||||
|
data: createInvite,
|
||||||
|
fragment: INVITE_FIELDS
|
||||||
|
})
|
||||||
|
return [newInviteRef, ...existingInviteRefs]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form
|
||||||
|
initial={{
|
||||||
|
gift: 100,
|
||||||
|
limit: undefined
|
||||||
|
}}
|
||||||
|
schema={InviteSchema}
|
||||||
|
onSubmit={async ({ limit, ...values }) => {
|
||||||
|
const { error } = await createInvite({
|
||||||
|
variables: {
|
||||||
|
...values, limit: limit ? Number(limit) : limit
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (error) {
|
||||||
|
throw new Error({ message: error.String() })
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
label='gift'
|
||||||
|
name='gift'
|
||||||
|
append={<InputGroup.Text className='text-monospace'>sats</InputGroup.Text>}
|
||||||
|
required
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
label={<>invitee limit <small className='text-muted ml-2'>optional</small></>}
|
||||||
|
name='limit'
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SubmitButton variant='secondary' className='mt-2'>create</SubmitButton>
|
||||||
|
</Form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Invites () {
|
||||||
|
const { data } = useQuery(
|
||||||
|
gql`
|
||||||
|
${INVITE_FIELDS}
|
||||||
|
{
|
||||||
|
invites {
|
||||||
|
...InviteFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<InviteForm />
|
||||||
|
{data && data.invites && data.invites.map(invite => {
|
||||||
|
return <div key={invite.id}>{invite.id}</div>
|
||||||
|
})}
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
|
@ -12,7 +12,6 @@ export async function getServerSideProps () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function PostForm () {
|
export function PostForm () {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "users" ADD COLUMN "inviteId" TEXT;
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Invite" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"userId" INTEGER NOT NULL,
|
||||||
|
"gift" INTEGER,
|
||||||
|
"limit" INTEGER,
|
||||||
|
"revoked" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
|
||||||
|
PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "users" ADD FOREIGN KEY ("inviteId") REFERENCES "Invite"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Invite" ADD FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
Loading…
Reference in New Issue