diff --git a/apps/api/app/api/v1/activity/route.ts b/apps/api/app/api/v1/activity/route.ts index 0d9c47b7..4c7ed06c 100644 --- a/apps/api/app/api/v1/activity/route.ts +++ b/apps/api/app/api/v1/activity/route.ts @@ -8,9 +8,9 @@ export const dynamic = 'force-dynamic' export async function GET(_req: Request): Promise> { try { - const activities = await getSiteActivity({}) + const data = await getSiteActivity({}) - return NextResponse.json({ activities }) + return NextResponse.json({ data }) } catch (error) { if (error instanceof CommentNotFoundError) { return NextResponse.json({ error: error.message }, { status: 404 }) diff --git a/apps/api/app/api/v1/activity/schema.ts b/apps/api/app/api/v1/activity/schema.ts index 40b0d7ff..fc72daec 100644 --- a/apps/api/app/api/v1/activity/schema.ts +++ b/apps/api/app/api/v1/activity/schema.ts @@ -4,8 +4,9 @@ import { MarketActivitySchema } from '@play-money/markets/types' export default { get: { + summary: 'Get all site activity', responses: { - 200: zod.object({ activities: zod.array(MarketActivitySchema) }), + 200: zod.object({ data: zod.array(MarketActivitySchema) }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/comments/[id]/reaction/route.ts b/apps/api/app/api/v1/comments/[id]/reaction/route.ts index 4eaa2fc7..5dc1cdb7 100644 --- a/apps/api/app/api/v1/comments/[id]/reaction/route.ts +++ b/apps/api/app/api/v1/comments/[id]/reaction/route.ts @@ -23,10 +23,10 @@ export async function POST( const commentReaction = await reactToComment({ commentId: id, userId, ...data }) if (commentReaction === 'removed') { - return NextResponse.json({ message: 'Reaction removed' }) + return new Response(null, { status: 204 }) as NextResponse> } - return NextResponse.json(commentReaction) + return NextResponse.json({ data: commentReaction }) } catch (error) { console.log(error) // eslint-disable-line no-console -- Log error for debugging return NextResponse.json({ error: 'Error processing request' }, { status: 500 }) diff --git a/apps/api/app/api/v1/comments/[id]/reaction/schema.ts b/apps/api/app/api/v1/comments/[id]/reaction/schema.ts index 60b60f13..49a1aec2 100644 --- a/apps/api/app/api/v1/comments/[id]/reaction/schema.ts +++ b/apps/api/app/api/v1/comments/[id]/reaction/schema.ts @@ -1,15 +1,18 @@ -import zod from 'zod' +import { z } from 'zod' import { ApiEndpoints, ServerErrorSchema } from '@play-money/api-helpers' import { CommentReactionSchema } from '@play-money/database' export default { post: { - parameters: zod.object({ id: zod.string() }), + summary: 'React to a comment, will remove reaction if already exists', + security: true, + parameters: z.object({ id: z.string() }), requestBody: CommentReactionSchema.pick({ emoji: true, }), responses: { - 200: [CommentReactionSchema, zod.object({ message: zod.string() })], + 200: z.object({ data: CommentReactionSchema }), + 204: z.object({}), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/comments/[id]/route.ts b/apps/api/app/api/v1/comments/[id]/route.ts index 0c98c5f0..53324a94 100644 --- a/apps/api/app/api/v1/comments/[id]/route.ts +++ b/apps/api/app/api/v1/comments/[id]/route.ts @@ -18,7 +18,7 @@ export async function GET( const comment = await getComment({ id }) - return NextResponse.json(comment) + return NextResponse.json({ data: comment }) } catch (error) { if (error instanceof CommentNotFoundError) { return NextResponse.json({ error: error.message }, { status: 404 }) @@ -51,7 +51,7 @@ export async function PATCH( const updatedComment = await updateComment({ id, content }) - return NextResponse.json(updatedComment) + return NextResponse.json({ data: updatedComment }) } catch (error) { if (error instanceof CommentNotFoundError) { return NextResponse.json({ error: error.message }, { status: 404 }) @@ -82,7 +82,7 @@ export async function DELETE( await deleteComment({ id }) - return NextResponse.json({ message: 'Comment deleted' }) + return new Response(null, { status: 204 }) as NextResponse> } catch (error) { if (error instanceof CommentNotFoundError) { return NextResponse.json({ error: error.message }, { status: 404 }) diff --git a/apps/api/app/api/v1/comments/[id]/schema.ts b/apps/api/app/api/v1/comments/[id]/schema.ts index d1b27a96..49371ad2 100644 --- a/apps/api/app/api/v1/comments/[id]/schema.ts +++ b/apps/api/app/api/v1/comments/[id]/schema.ts @@ -4,26 +4,31 @@ import { CommentSchema } from '@play-money/database' export default { get: { + summary: 'Get a comment', parameters: CommentSchema.pick({ id: true }), responses: { - 200: CommentSchema, + 200: z.object({ data: CommentSchema }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, }, patch: { + summary: 'Update a comment', + security: true, parameters: CommentSchema.pick({ id: true }), requestBody: CommentSchema.pick({ content: true }), responses: { - 200: CommentSchema, + 200: z.object({ data: CommentSchema }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, }, delete: { + summary: 'Delete a comment', + security: true, parameters: CommentSchema.pick({ id: true }), responses: { - 200: z.object({ message: z.string() }), + 204: z.object({}), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/comments/route.ts b/apps/api/app/api/v1/comments/route.ts index 0a800c2b..cba5a027 100644 --- a/apps/api/app/api/v1/comments/route.ts +++ b/apps/api/app/api/v1/comments/route.ts @@ -18,7 +18,7 @@ export async function POST(req: Request): Promise> { - try { - const transactions = await getNewLiquidityTransactions() - - return NextResponse.json({ - transactions, - }) - } catch (error) { - console.log(error) // eslint-disable-line no-console -- Log error for debugging - - if (error instanceof UserNotFoundError) { - return NextResponse.json({ error: error.message }, { status: 404 }) - } - - return NextResponse.json({ error: 'Error processing request' }, { status: 500 }) - } -} diff --git a/apps/api/app/api/v1/liquidity/schema.ts b/apps/api/app/api/v1/liquidity/schema.ts deleted file mode 100644 index f69ff45d..00000000 --- a/apps/api/app/api/v1/liquidity/schema.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { z } from 'zod' -import { ApiEndpoints, ServerErrorSchema } from '@play-money/api-helpers' -import { MarketSchema, TransactionEntrySchema, TransactionSchema, UserSchema } from '@play-money/database' - -export default { - get: { - responses: { - 200: z.object({ - transactions: z.array( - TransactionSchema.extend({ - entries: z.array(TransactionEntrySchema), - market: MarketSchema.or(z.null()), - initiator: UserSchema.or(z.null()), - }) - ), - }), - 404: ServerErrorSchema, - 500: ServerErrorSchema, - }, - }, -} as const satisfies ApiEndpoints diff --git a/apps/api/app/api/v1/lists/[id]/balance/route.ts b/apps/api/app/api/v1/lists/[id]/balance/route.ts index eb82dcc3..b1108b7b 100644 --- a/apps/api/app/api/v1/lists/[id]/balance/route.ts +++ b/apps/api/app/api/v1/lists/[id]/balance/route.ts @@ -43,8 +43,10 @@ export async function GET( ]) return NextResponse.json({ - user: transformMarketBalancesToNumbers(userBalancesInList), - userPositions: transformMarketOptionPositionToNumbers(userPositions), + data: { + user: transformMarketBalancesToNumbers(userBalancesInList), + userPositions: transformMarketOptionPositionToNumbers(userPositions), + }, }) } catch (error) { console.log(error) // eslint-disable-line no-console -- Log error for debugging diff --git a/apps/api/app/api/v1/lists/[id]/balance/schema.ts b/apps/api/app/api/v1/lists/[id]/balance/schema.ts index 130b0b2c..476c1150 100644 --- a/apps/api/app/api/v1/lists/[id]/balance/schema.ts +++ b/apps/api/app/api/v1/lists/[id]/balance/schema.ts @@ -3,12 +3,15 @@ import { ApiEndpoints, ServerErrorSchema } from '@play-money/api-helpers' export default { get: { + summary: 'Get the balance for a list', parameters: z.object({ id: z.string() }), responses: { 200: z.object({ - // TODO: Hookup with NetBalance - user: z.array(z.object({})), - userPositions: z.array(z.object({})), + data: z.object({ + // TODO: Hookup with NetBalance + user: z.array(z.object({})), + userPositions: z.array(z.object({})), + }), }), 404: ServerErrorSchema, 500: ServerErrorSchema, diff --git a/apps/api/app/api/v1/lists/[id]/comments/route.ts b/apps/api/app/api/v1/lists/[id]/comments/route.ts index 5417c829..0afcbcff 100644 --- a/apps/api/app/api/v1/lists/[id]/comments/route.ts +++ b/apps/api/app/api/v1/lists/[id]/comments/route.ts @@ -15,7 +15,7 @@ export async function GET( const comments = await getCommentsOnList({ listId: id }) - return NextResponse.json({ comments }) + return NextResponse.json({ data: comments }) } catch (error) { if (error instanceof CommentNotFoundError) { return NextResponse.json({ error: error.message }, { status: 404 }) diff --git a/apps/api/app/api/v1/lists/[id]/comments/schema.ts b/apps/api/app/api/v1/lists/[id]/comments/schema.ts index 27af59c3..9d998dc3 100644 --- a/apps/api/app/api/v1/lists/[id]/comments/schema.ts +++ b/apps/api/app/api/v1/lists/[id]/comments/schema.ts @@ -4,9 +4,10 @@ import { CommentSchema } from '@play-money/database' export default { get: { + summary: 'Get comments for a list', parameters: zod.object({ id: zod.string() }), responses: { - 200: zod.object({ comments: zod.array(CommentSchema) }), + 200: zod.object({ data: zod.array(CommentSchema) }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/lists/[id]/markets/route.ts b/apps/api/app/api/v1/lists/[id]/markets/route.ts index 68c06b37..3121249a 100644 --- a/apps/api/app/api/v1/lists/[id]/markets/route.ts +++ b/apps/api/app/api/v1/lists/[id]/markets/route.ts @@ -62,7 +62,7 @@ export async function POST( }, }) - return NextResponse.json({ market: newMarket }) + return NextResponse.json({ data: newMarket }) } catch (error: unknown) { console.log(error) // eslint-disable-line no-console -- Log error for debugging if (error instanceof Error) { diff --git a/apps/api/app/api/v1/lists/[id]/markets/schema.ts b/apps/api/app/api/v1/lists/[id]/markets/schema.ts index 052032d1..1c9bfee4 100644 --- a/apps/api/app/api/v1/lists/[id]/markets/schema.ts +++ b/apps/api/app/api/v1/lists/[id]/markets/schema.ts @@ -4,6 +4,8 @@ import { MarketOptionSchema, MarketSchema } from '@play-money/database' export default { post: { + summary: 'Create a market in a list', + security: true, parameters: z.object({ id: z.string() }), requestBody: MarketSchema.pick({ question: true, @@ -19,7 +21,7 @@ export default { ), }), responses: { - 200: z.object({ market: MarketSchema.optional() }), + 200: z.object({ data: MarketSchema }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/lists/[id]/route.ts b/apps/api/app/api/v1/lists/[id]/route.ts index 9b83d180..888450e3 100644 --- a/apps/api/app/api/v1/lists/[id]/route.ts +++ b/apps/api/app/api/v1/lists/[id]/route.ts @@ -24,7 +24,7 @@ export async function GET( const list = await getList({ id, extended }) - return NextResponse.json(list) + return NextResponse.json({ data: list }) } catch (error) { console.log(error) // eslint-disable-line no-console -- Log error for debugging return NextResponse.json({ error: 'Error processing request' }, { status: 500 }) diff --git a/apps/api/app/api/v1/lists/[id]/schema.ts b/apps/api/app/api/v1/lists/[id]/schema.ts index 6bd19182..ff393c2d 100644 --- a/apps/api/app/api/v1/lists/[id]/schema.ts +++ b/apps/api/app/api/v1/lists/[id]/schema.ts @@ -4,9 +4,10 @@ import { ListSchema } from '@play-money/database' export default { get: { + summary: 'Get a list', parameters: ListSchema.pick({ id: true }).extend({ extended: z.boolean().optional() }), responses: { - 200: ListSchema, + 200: z.object({ data: ListSchema }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/lists/route.ts b/apps/api/app/api/v1/lists/route.ts index eb625349..0844def5 100644 --- a/apps/api/app/api/v1/lists/route.ts +++ b/apps/api/app/api/v1/lists/route.ts @@ -11,19 +11,11 @@ export async function GET(req: Request): Promise> { - try { - const url = new URL(req.url) - const searchParams = new URLSearchParams(url.search) - const params = Object.fromEntries(searchParams) - - const { - ownerId, - marketId, - status, - pageSize = 50, - page = 1, - sortField, - sortDirection = 'desc', - } = schema.get.parameters.parse(params) ?? {} - - const { marketPositions, total } = await getMarketPositions( - { ownerId, status, marketId }, - sortField - ? { - field: sortField, - direction: sortDirection, - } - : undefined, - { - skip: (page - 1) * pageSize, - take: pageSize, - } - ) - - return NextResponse.json({ - marketPositions, - page, - pageSize, - totalPages: Math.ceil(total / pageSize), - }) - } catch (error) { - console.log(error) // eslint-disable-line no-console -- Log error for debugging - if (error instanceof Error) { - return NextResponse.json({ error: error.message }, { status: 500 }) - } - - return NextResponse.json({ error: 'Error processing request' }, { status: 500 }) - } -} diff --git a/apps/api/app/api/v1/market-positions/schema.ts b/apps/api/app/api/v1/market-positions/schema.ts deleted file mode 100644 index ab11a502..00000000 --- a/apps/api/app/api/v1/market-positions/schema.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { z } from 'zod' -import { ApiEndpoints, ServerErrorSchema } from '@play-money/api-helpers' -import { MarketOptionPositionSchema } from '@play-money/database' - -export default { - get: { - parameters: z - .object({ - status: z.enum(['active', 'closed', 'all']).optional(), - ownerId: z.string().optional(), - marketId: z.string().optional(), - pageSize: z.coerce.number().optional(), - page: z.coerce.number().optional(), - sortField: z.string().optional(), - sortDirection: z.enum(['asc', 'desc']).optional(), - }) - .optional(), - responses: { - 200: z.object({ - marketPositions: z.array(MarketOptionPositionSchema), - page: z.number(), - pageSize: z.number(), - totalPages: z.number(), - }), - 404: ServerErrorSchema, - 500: ServerErrorSchema, - }, - }, -} as const satisfies ApiEndpoints diff --git a/apps/api/app/api/v1/markets/[id]/activity/route.ts b/apps/api/app/api/v1/markets/[id]/activity/route.ts index 5d2e5b9e..d321c24d 100644 --- a/apps/api/app/api/v1/markets/[id]/activity/route.ts +++ b/apps/api/app/api/v1/markets/[id]/activity/route.ts @@ -13,9 +13,9 @@ export async function GET( try { const { id } = schema.get.parameters.parse(params) - const activities = await getActivityOnMarket({ marketId: id }) + const data = await getActivityOnMarket({ marketId: id }) - return NextResponse.json({ activities }) + return NextResponse.json({ data }) } catch (error) { if (error instanceof CommentNotFoundError) { return NextResponse.json({ error: error.message }, { status: 404 }) diff --git a/apps/api/app/api/v1/markets/[id]/activity/schema.ts b/apps/api/app/api/v1/markets/[id]/activity/schema.ts index 2486252e..ec258048 100644 --- a/apps/api/app/api/v1/markets/[id]/activity/schema.ts +++ b/apps/api/app/api/v1/markets/[id]/activity/schema.ts @@ -4,9 +4,10 @@ import { MarketActivitySchema } from '@play-money/markets/types' export default { get: { + summary: 'Get the activity for a market', parameters: zod.object({ id: zod.string() }), responses: { - 200: zod.object({ activities: zod.array(MarketActivitySchema) }), + 200: zod.object({ data: zod.array(MarketActivitySchema) }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/markets/[id]/balance/route.ts b/apps/api/app/api/v1/markets/[id]/balance/route.ts index 9d012bde..ba17c006 100644 --- a/apps/api/app/api/v1/markets/[id]/balance/route.ts +++ b/apps/api/app/api/v1/markets/[id]/balance/route.ts @@ -32,9 +32,11 @@ export async function GET( ]) return NextResponse.json({ - amm: transformMarketBalancesToNumbers(ammBalances), - user: transformMarketBalancesToNumbers(userBalancesInMarket), - userPositions: transformMarketOptionPositionToNumbers(userPositions), + data: { + amm: transformMarketBalancesToNumbers(ammBalances), + user: transformMarketBalancesToNumbers(userBalancesInMarket), + userPositions: transformMarketOptionPositionToNumbers(userPositions), + }, }) } catch (error) { console.log(error) // eslint-disable-line no-console -- Log error for debugging diff --git a/apps/api/app/api/v1/markets/[id]/balance/schema.ts b/apps/api/app/api/v1/markets/[id]/balance/schema.ts index 01a81ffd..bb80b8bd 100644 --- a/apps/api/app/api/v1/markets/[id]/balance/schema.ts +++ b/apps/api/app/api/v1/markets/[id]/balance/schema.ts @@ -3,13 +3,16 @@ import { ApiEndpoints, ServerErrorSchema } from '@play-money/api-helpers' export default { get: { + summary: 'Get the balance for a market', parameters: z.object({ id: z.string() }), responses: { 200: z.object({ - // TODO: Hookup with NetBalance - amm: z.array(z.object({})), - user: z.array(z.object({})), - userPositions: z.array(z.object({})), + data: z.object({ + // TODO: Hookup with NetBalance + amm: z.array(z.object({})), + user: z.array(z.object({})), + userPositions: z.array(z.object({})), + }), }), 404: ServerErrorSchema, 500: ServerErrorSchema, diff --git a/apps/api/app/api/v1/markets/[id]/balances/route.ts b/apps/api/app/api/v1/markets/[id]/balances/route.ts new file mode 100644 index 00000000..958d4a27 --- /dev/null +++ b/apps/api/app/api/v1/markets/[id]/balances/route.ts @@ -0,0 +1,78 @@ +import Decimal from 'decimal.js' +import { NextResponse } from 'next/server' +import type { SchemaResponse } from '@play-money/api-helpers' +import { getAuthUser } from '@play-money/auth/lib/getAuthUser' +import db from '@play-money/database' +import type { NetBalance } from '@play-money/finance/lib/getBalances' +import { transformMarketBalancesToNumbers } from '@play-money/finance/lib/getBalances' +import { getUserPrimaryAccount } from '@play-money/users/lib/getUserPrimaryAccount' +import schema from './schema' + +export const dynamic = 'force-dynamic' + +export async function GET( + req: Request, + { params }: { params: unknown } +): Promise> { + try { + const { id } = schema.get.parameters.parse(params) + const userId = await getAuthUser(req) + const userAccount = userId ? await getUserPrimaryAccount({ userId }) : undefined + + const [userBalances, userBalancesInMarket] = await Promise.all([ + db.balance.findMany({ + where: { + marketId: id, + assetType: 'CURRENCY', + assetId: 'PRIMARY', + account: { + NOT: { + userPrimary: null, + }, + }, + total: { + gt: new Decimal(0), + }, + }, + orderBy: { + total: 'desc', + }, + include: { + account: { + include: { + userPrimary: true, + }, + }, + }, + take: 5, + }) as unknown as Array, + userAccount + ? (db.balance.findFirst({ + where: { + accountId: userAccount.id, + assetType: 'CURRENCY', + assetId: 'PRIMARY', + marketId: id, + }, + include: { + account: { + include: { + userPrimary: true, + }, + }, + }, + }) as unknown as NetBalance | undefined) + : undefined, + ]) + + return NextResponse.json({ + data: { + balances: transformMarketBalancesToNumbers(userBalances), + user: userBalancesInMarket ? transformMarketBalancesToNumbers([userBalancesInMarket])[0] : undefined, + }, + }) + } catch (error) { + console.log(error) // eslint-disable-line no-console -- Log error for debugging + return NextResponse.json({ error: 'Error processing request' }, { status: 500 }) + } +} diff --git a/apps/api/app/api/v1/markets/[id]/balances/schema.ts b/apps/api/app/api/v1/markets/[id]/balances/schema.ts new file mode 100644 index 00000000..a5529a3b --- /dev/null +++ b/apps/api/app/api/v1/markets/[id]/balances/schema.ts @@ -0,0 +1,20 @@ +import { z } from 'zod' +import { ApiEndpoints, ServerErrorSchema } from '@play-money/api-helpers' + +export default { + get: { + summary: 'Get the balances for a market', + parameters: z.object({ id: z.string() }), + responses: { + 200: z.object({ + data: z.object({ + // TODO: Hookup with NetBalance + balances: z.array(z.object({})), + user: z.object({}).optional(), + }), + }), + 404: ServerErrorSchema, + 500: ServerErrorSchema, + }, + }, +} as const satisfies ApiEndpoints diff --git a/apps/api/app/api/v1/markets/[id]/buy/route.ts b/apps/api/app/api/v1/markets/[id]/buy/route.ts index 2b92485d..56ff4027 100644 --- a/apps/api/app/api/v1/markets/[id]/buy/route.ts +++ b/apps/api/app/api/v1/markets/[id]/buy/route.ts @@ -29,7 +29,7 @@ export async function POST( userId, }) - return NextResponse.json({}) + return NextResponse.json({ data: { success: true } }) } catch (error) { console.log(error) // eslint-disable-line no-console -- Log error for debugging return NextResponse.json({ error: 'Error processing request' }, { status: 500 }) diff --git a/apps/api/app/api/v1/markets/[id]/buy/schema.ts b/apps/api/app/api/v1/markets/[id]/buy/schema.ts index a2056c87..9158053b 100644 --- a/apps/api/app/api/v1/markets/[id]/buy/schema.ts +++ b/apps/api/app/api/v1/markets/[id]/buy/schema.ts @@ -3,10 +3,12 @@ import { ApiEndpoints, ServerErrorSchema } from '@play-money/api-helpers' export default { post: { + summary: 'Buy an option in a market', + security: true, parameters: z.object({ id: z.string() }), requestBody: z.object({ optionId: z.string(), amount: z.number() }), responses: { - 200: z.object({}), + 200: z.object({ data: z.object({ success: z.boolean() }) }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/markets/[id]/cancel/route.ts b/apps/api/app/api/v1/markets/[id]/cancel/route.ts index ed77f393..5a91925f 100644 --- a/apps/api/app/api/v1/markets/[id]/cancel/route.ts +++ b/apps/api/app/api/v1/markets/[id]/cancel/route.ts @@ -37,7 +37,7 @@ export async function POST( reason, }) - return NextResponse.json({}) + return NextResponse.json({ data: { success: true } }) } catch (error) { console.log(error) // eslint-disable-line no-console -- Log error for debugging if (error instanceof Error) { diff --git a/apps/api/app/api/v1/markets/[id]/cancel/schema.ts b/apps/api/app/api/v1/markets/[id]/cancel/schema.ts index 5e927426..7b499b8f 100644 --- a/apps/api/app/api/v1/markets/[id]/cancel/schema.ts +++ b/apps/api/app/api/v1/markets/[id]/cancel/schema.ts @@ -3,10 +3,12 @@ import { ApiEndpoints, ServerErrorSchema } from '@play-money/api-helpers' export default { post: { + summary: 'Cancel a market', + security: true, parameters: z.object({ id: z.string() }), requestBody: z.object({ reason: z.string() }), responses: { - 200: z.object({}), + 200: z.object({ data: z.object({ success: z.boolean() }) }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/markets/[id]/comments/route.ts b/apps/api/app/api/v1/markets/[id]/comments/route.ts index 4f94a512..ab12e945 100644 --- a/apps/api/app/api/v1/markets/[id]/comments/route.ts +++ b/apps/api/app/api/v1/markets/[id]/comments/route.ts @@ -15,7 +15,7 @@ export async function GET( const comments = await getCommentsOnMarket({ marketId: id }) - return NextResponse.json({ comments }) + return NextResponse.json({ data: comments }) } catch (error) { if (error instanceof CommentNotFoundError) { return NextResponse.json({ error: error.message }, { status: 404 }) diff --git a/apps/api/app/api/v1/markets/[id]/comments/schema.ts b/apps/api/app/api/v1/markets/[id]/comments/schema.ts index 27af59c3..ddc188ab 100644 --- a/apps/api/app/api/v1/markets/[id]/comments/schema.ts +++ b/apps/api/app/api/v1/markets/[id]/comments/schema.ts @@ -4,9 +4,10 @@ import { CommentSchema } from '@play-money/database' export default { get: { + summary: 'Get comments for a market', parameters: zod.object({ id: zod.string() }), responses: { - 200: zod.object({ comments: zod.array(CommentSchema) }), + 200: zod.object({ data: zod.array(CommentSchema) }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/markets/[id]/graph/schema.ts b/apps/api/app/api/v1/markets/[id]/graph/schema.ts index 1cb5c5cf..76829740 100644 --- a/apps/api/app/api/v1/markets/[id]/graph/schema.ts +++ b/apps/api/app/api/v1/markets/[id]/graph/schema.ts @@ -3,6 +3,7 @@ import { ApiEndpoints, ServerErrorSchema } from '@play-money/api-helpers' export default { get: { + summary: 'Get the graph for a market', parameters: z.object({ id: z.string() }), responses: { 200: z.object({ diff --git a/apps/api/app/api/v1/markets/[id]/liquidity/route.ts b/apps/api/app/api/v1/markets/[id]/liquidity/route.ts index 8ed58be7..74a94790 100644 --- a/apps/api/app/api/v1/markets/[id]/liquidity/route.ts +++ b/apps/api/app/api/v1/markets/[id]/liquidity/route.ts @@ -29,7 +29,9 @@ export async function POST( }) return NextResponse.json({ - message: 'success', + data: { + success: true, + }, }) } catch (error) { console.log(error) // eslint-disable-line no-console -- Log error for debugging diff --git a/apps/api/app/api/v1/markets/[id]/liquidity/schema.ts b/apps/api/app/api/v1/markets/[id]/liquidity/schema.ts index f2465315..3386a75a 100644 --- a/apps/api/app/api/v1/markets/[id]/liquidity/schema.ts +++ b/apps/api/app/api/v1/markets/[id]/liquidity/schema.ts @@ -4,11 +4,15 @@ import { MarketSchema } from '@play-money/database' export default { post: { + summary: 'Add liquidity to a market', + security: true, parameters: MarketSchema.pick({ id: true }), requestBody: z.object({ amount: z.number() }), responses: { 200: z.object({ - message: z.string(), + data: z.object({ + success: z.boolean(), + }), }), 404: ServerErrorSchema, 500: ServerErrorSchema, diff --git a/apps/api/app/api/v1/markets/[id]/options/[optionId]/route.ts b/apps/api/app/api/v1/markets/[id]/options/[optionId]/route.ts index cdb942b0..ed17b927 100644 --- a/apps/api/app/api/v1/markets/[id]/options/[optionId]/route.ts +++ b/apps/api/app/api/v1/markets/[id]/options/[optionId]/route.ts @@ -33,7 +33,7 @@ export async function PATCH( const updatedComment = await updateMarketOption({ id: optionId, name, color }) - return NextResponse.json(updatedComment) + return NextResponse.json({ data: updatedComment }) } catch (error) { if (error instanceof CommentNotFoundError) { return NextResponse.json({ error: error.message }, { status: 404 }) diff --git a/apps/api/app/api/v1/markets/[id]/options/[optionId]/schema.ts b/apps/api/app/api/v1/markets/[id]/options/[optionId]/schema.ts index 9e048de1..8bbdb61d 100644 --- a/apps/api/app/api/v1/markets/[id]/options/[optionId]/schema.ts +++ b/apps/api/app/api/v1/markets/[id]/options/[optionId]/schema.ts @@ -4,10 +4,12 @@ import { MarketOptionSchema } from '@play-money/database' export default { patch: { + summary: 'Update an option in a market', + security: true, parameters: z.object({ id: z.string(), optionId: z.string() }), requestBody: MarketOptionSchema.pick({ name: true, color: true }).partial(), responses: { - 200: MarketOptionSchema, + 200: z.object({ data: MarketOptionSchema }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/markets/[id]/positions/route.ts b/apps/api/app/api/v1/markets/[id]/positions/route.ts index 7f0b4f4f..6f8a08f7 100644 --- a/apps/api/app/api/v1/markets/[id]/positions/route.ts +++ b/apps/api/app/api/v1/markets/[id]/positions/route.ts @@ -1,76 +1,36 @@ -import Decimal from 'decimal.js' import { NextResponse } from 'next/server' import type { SchemaResponse } from '@play-money/api-helpers' -import { getAuthUser } from '@play-money/auth/lib/getAuthUser' -import db from '@play-money/database' -import type { NetBalance } from '@play-money/finance/lib/getBalances' -import { transformMarketBalancesToNumbers } from '@play-money/finance/lib/getBalances' -import { getUserPrimaryAccount } from '@play-money/users/lib/getUserPrimaryAccount' +import { getMarketPositions } from '@play-money/markets/lib/getMarketPositions' import schema from './schema' export const dynamic = 'force-dynamic' +// TODO: Look into a better way to handle mixing vercel params and search params together... export async function GET( req: Request, - { params }: { params: unknown } + { params: idParams }: { params: Record } ): Promise> { try { - const { id } = schema.get.parameters.parse(params) - const userId = await getAuthUser(req) - const userAccount = userId ? await getUserPrimaryAccount({ userId }) : undefined + const url = new URL(req.url) + const searchParams = new URLSearchParams(url.search) + const params = Object.fromEntries(searchParams) - const [userBalances, userBalancesInMarket] = await Promise.all([ - db.balance.findMany({ - where: { - marketId: id, - assetType: 'CURRENCY', - assetId: 'PRIMARY', - account: { - NOT: { - userPrimary: null, - }, - }, - total: { - gt: new Decimal(0), - }, - }, - orderBy: { - total: 'desc', - }, - include: { - account: { - include: { - userPrimary: true, - }, - }, - }, - take: 5, - }) as unknown as Array, - userAccount - ? (db.balance.findFirst({ - where: { - accountId: userAccount.id, - assetType: 'CURRENCY', - assetId: 'PRIMARY', - marketId: id, - }, - include: { - account: { - include: { - userPrimary: true, - }, - }, - }, - }) as unknown as NetBalance | undefined) - : undefined, - ]) + const { + ownerId, + id: marketId, + status, + ...paginationParams + } = schema.get.parameters.parse({ ...params, ...idParams }) ?? {} - return NextResponse.json({ - balances: transformMarketBalancesToNumbers(userBalances), - user: userBalancesInMarket ? transformMarketBalancesToNumbers([userBalancesInMarket])[0] : undefined, - }) + const results = await getMarketPositions({ ownerId, status, marketId }, paginationParams) + + return NextResponse.json(results) } catch (error) { console.log(error) // eslint-disable-line no-console -- Log error for debugging + if (error instanceof Error) { + return NextResponse.json({ error: error.message }, { status: 500 }) + } + return NextResponse.json({ error: 'Error processing request' }, { status: 500 }) } } diff --git a/apps/api/app/api/v1/markets/[id]/positions/schema.ts b/apps/api/app/api/v1/markets/[id]/positions/schema.ts index 45cc8be5..caa1ef65 100644 --- a/apps/api/app/api/v1/markets/[id]/positions/schema.ts +++ b/apps/api/app/api/v1/markets/[id]/positions/schema.ts @@ -1,15 +1,25 @@ import { z } from 'zod' -import { ApiEndpoints, ServerErrorSchema } from '@play-money/api-helpers' +import { + ApiEndpoints, + createPaginatedResponseSchema, + paginationSchema, + ServerErrorSchema, +} from '@play-money/api-helpers' +import { MarketOptionPositionSchema } from '@play-money/database' export default { get: { - parameters: z.object({ id: z.string() }), + summary: 'Get positions for a market', + parameters: z + .object({ + id: z.string(), + status: z.enum(['active', 'closed', 'all']).optional(), + ownerId: z.string().optional(), + }) + .merge(paginationSchema) + .optional(), responses: { - 200: z.object({ - // TODO: Hookup with NetBalance - balances: z.array(z.object({})), - user: z.object({}).optional(), - }), + 200: createPaginatedResponseSchema(MarketOptionPositionSchema), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/markets/[id]/quote/route.ts b/apps/api/app/api/v1/markets/[id]/quote/route.ts index 461eb35b..072cee55 100644 --- a/apps/api/app/api/v1/markets/[id]/quote/route.ts +++ b/apps/api/app/api/v1/markets/[id]/quote/route.ts @@ -24,8 +24,10 @@ export async function POST( }) return NextResponse.json({ - newProbability: probability.toNumber(), - potentialReturn: shares.toNumber(), + data: { + newProbability: probability.toNumber(), + potentialReturn: shares.toNumber(), + }, }) } catch (error) { console.log(error) // eslint-disable-line no-console -- Log error for debugging diff --git a/apps/api/app/api/v1/markets/[id]/quote/schema.ts b/apps/api/app/api/v1/markets/[id]/quote/schema.ts index 46174cb4..9adf2d9a 100644 --- a/apps/api/app/api/v1/markets/[id]/quote/schema.ts +++ b/apps/api/app/api/v1/markets/[id]/quote/schema.ts @@ -3,12 +3,15 @@ import { ApiEndpoints, ServerErrorSchema } from '@play-money/api-helpers' export default { post: { + summary: 'Get a quote for a market', parameters: z.object({ id: z.string() }), requestBody: z.object({ optionId: z.string(), amount: z.number(), isBuy: z.boolean().optional() }), responses: { 200: z.object({ - newProbability: z.number(), - potentialReturn: z.number(), + data: z.object({ + newProbability: z.number(), + potentialReturn: z.number(), + }), }), 404: ServerErrorSchema, 500: ServerErrorSchema, diff --git a/apps/api/app/api/v1/markets/[id]/related/route.ts b/apps/api/app/api/v1/markets/[id]/related/route.ts index 90330e50..494b1e6e 100644 --- a/apps/api/app/api/v1/markets/[id]/related/route.ts +++ b/apps/api/app/api/v1/markets/[id]/related/route.ts @@ -14,7 +14,7 @@ export async function GET( const markets = await getRelatedMarkets({ marketId: id }) - return NextResponse.json({ markets }) + return NextResponse.json({ data: markets }) } catch (error) { console.log(error) // eslint-disable-line no-console -- Log error for debugging return NextResponse.json({ error: 'Error processing request' }, { status: 500 }) diff --git a/apps/api/app/api/v1/markets/[id]/related/schema.ts b/apps/api/app/api/v1/markets/[id]/related/schema.ts index cf6392ac..9b6bcfd1 100644 --- a/apps/api/app/api/v1/markets/[id]/related/schema.ts +++ b/apps/api/app/api/v1/markets/[id]/related/schema.ts @@ -1,12 +1,13 @@ -import zod from 'zod' +import { z } from 'zod' import { ApiEndpoints, ServerErrorSchema } from '@play-money/api-helpers' import { MarketSchema } from '@play-money/database' export default { get: { - parameters: zod.object({ id: zod.string() }), + summary: 'Get related markets', + parameters: z.object({ id: z.string() }), responses: { - 200: zod.object({ markets: zod.array(MarketSchema) }), + 200: z.object({ data: z.array(MarketSchema) }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/markets/[id]/resolve/route.ts b/apps/api/app/api/v1/markets/[id]/resolve/route.ts index d53d5e53..ecb823ed 100644 --- a/apps/api/app/api/v1/markets/[id]/resolve/route.ts +++ b/apps/api/app/api/v1/markets/[id]/resolve/route.ts @@ -38,7 +38,7 @@ export async function POST( supportingLink, }) - return NextResponse.json({}) + return NextResponse.json({ data: { success: true } }) } catch (error) { console.log(error) // eslint-disable-line no-console -- Log error for debugging if (error instanceof Error) { diff --git a/apps/api/app/api/v1/markets/[id]/resolve/schema.ts b/apps/api/app/api/v1/markets/[id]/resolve/schema.ts index f46bdf90..0aaac568 100644 --- a/apps/api/app/api/v1/markets/[id]/resolve/schema.ts +++ b/apps/api/app/api/v1/markets/[id]/resolve/schema.ts @@ -3,10 +3,12 @@ import { ApiEndpoints, ServerErrorSchema } from '@play-money/api-helpers' export default { post: { + summary: 'Resolve a market', + security: true, parameters: z.object({ id: z.string() }), requestBody: z.object({ optionId: z.string(), supportingLink: z.string().optional() }), responses: { - 200: z.object({}), + 200: z.object({ data: z.object({ success: z.boolean() }) }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/markets/[id]/route.ts b/apps/api/app/api/v1/markets/[id]/route.ts index 961c84d2..fb8e2239 100644 --- a/apps/api/app/api/v1/markets/[id]/route.ts +++ b/apps/api/app/api/v1/markets/[id]/route.ts @@ -28,7 +28,7 @@ export async function GET( const { id, extended } = schema.get.parameters.parse({ ...params, ...idParams }) const market = await getMarket({ id, extended }) - return NextResponse.json(market) + return NextResponse.json({ data: market }) } catch (error) { console.log(error) // eslint-disable-line no-console -- Log error for debugging return NextResponse.json({ error: 'Error processing request' }, { status: 500 }) @@ -47,7 +47,9 @@ export async function PATCH( const { id } = schema.patch.parameters.parse(params) const body = (await req.json()) as unknown - const { question, description, closeDate, tags } = schema.patch.requestBody.transform(stripUndefined).parse(body) + const { question, description, closeDate, tags, createdBy } = schema.patch.requestBody + .transform(stripUndefined) + .parse(body) const market = await getMarket({ id }) const user = await getUserById({ id: userId }) @@ -56,9 +58,9 @@ export async function PATCH( return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } - const updatedMarket = await updateMarket({ id, question, description, closeDate, tags }) + const updatedMarket = await updateMarket({ id, question, description, closeDate, tags, createdBy }) - return NextResponse.json(updatedMarket) + return NextResponse.json({ data: updatedMarket }) } catch (error) { if (error instanceof CommentNotFoundError) { return NextResponse.json({ error: error.message }, { status: 404 }) diff --git a/apps/api/app/api/v1/markets/[id]/schema.ts b/apps/api/app/api/v1/markets/[id]/schema.ts index d203acc0..16c4d77b 100644 --- a/apps/api/app/api/v1/markets/[id]/schema.ts +++ b/apps/api/app/api/v1/markets/[id]/schema.ts @@ -4,18 +4,27 @@ import { MarketSchema } from '@play-money/database' export default { get: { + summary: 'Get a market', parameters: MarketSchema.pick({ id: true }).extend({ extended: z.boolean().optional() }), responses: { - 200: MarketSchema, + 200: z.object({ data: MarketSchema }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, }, patch: { + summary: 'Update a market', + security: true, parameters: MarketSchema.pick({ id: true }), - requestBody: MarketSchema.pick({ question: true, description: true, closeDate: true, tags: true }).partial(), + requestBody: MarketSchema.pick({ + question: true, + description: true, + closeDate: true, + tags: true, + createdBy: true, + }).partial(), responses: { - 200: MarketSchema, + 200: z.object({ data: MarketSchema }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/markets/[id]/sell/route.ts b/apps/api/app/api/v1/markets/[id]/sell/route.ts index 4001ad7b..a34ee4a3 100644 --- a/apps/api/app/api/v1/markets/[id]/sell/route.ts +++ b/apps/api/app/api/v1/markets/[id]/sell/route.ts @@ -29,7 +29,7 @@ export async function POST( amount: new Decimal(amount), }) - return NextResponse.json({}) + return NextResponse.json({ data: { success: true } }) } catch (error) { console.log(error) // eslint-disable-line no-console -- Log error for debugging return NextResponse.json({ error: 'Error processing request' }, { status: 500 }) diff --git a/apps/api/app/api/v1/markets/[id]/sell/schema.ts b/apps/api/app/api/v1/markets/[id]/sell/schema.ts index a2056c87..7a86a55c 100644 --- a/apps/api/app/api/v1/markets/[id]/sell/schema.ts +++ b/apps/api/app/api/v1/markets/[id]/sell/schema.ts @@ -3,10 +3,12 @@ import { ApiEndpoints, ServerErrorSchema } from '@play-money/api-helpers' export default { post: { + summary: 'Sell an option in a market', + security: true, parameters: z.object({ id: z.string() }), requestBody: z.object({ optionId: z.string(), amount: z.number() }), responses: { - 200: z.object({}), + 200: z.object({ data: z.object({ success: z.boolean() }) }), 404: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/markets/generate-tags/route.ts b/apps/api/app/api/v1/markets/generate-tags/route.ts index 5d27d282..2a1c8898 100644 --- a/apps/api/app/api/v1/markets/generate-tags/route.ts +++ b/apps/api/app/api/v1/markets/generate-tags/route.ts @@ -13,7 +13,7 @@ export async function POST(req: Request): Promise> { try { - const userId = await getAuthUser(req) - if (!userId) { + const session = await auth() + + if (!session?.user?.id) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } @@ -21,11 +22,11 @@ export async function POST(req: Request): Promise> { +export async function GET(): Promise> { try { - const userId = await getAuthUser(req) - if (!userId) { + const session = await auth() + + if (!session?.user?.id) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } const keys = await db.apiKey.findMany({ where: { - userId, + userId: session.user.id, isRevoked: false, }, }) - return NextResponse.json({ keys }) + return NextResponse.json({ data: keys }) } catch (error) { console.log(error) // eslint-disable-line no-console -- Log error for debugging diff --git a/apps/api/app/api/v1/users/me/api-keys/schema.ts b/apps/api/app/api/v1/users/me/api-keys/schema.ts index 41794806..440911e1 100644 --- a/apps/api/app/api/v1/users/me/api-keys/schema.ts +++ b/apps/api/app/api/v1/users/me/api-keys/schema.ts @@ -4,18 +4,24 @@ import { ApiKeySchema } from '@play-money/database' export default { post: { + private: true, + summary: 'Create an API key', + security: true, requestBody: z.object({ name: z.string(), }), responses: { - 200: ApiKeySchema, + 200: z.object({ data: ApiKeySchema }), 401: ServerErrorSchema, 500: ServerErrorSchema, }, }, get: { + private: true, + summary: 'Get all API keys for a user', + security: true, responses: { - 200: z.object({ keys: z.array(ApiKeySchema) }), + 200: z.object({ data: z.array(ApiKeySchema) }), 401: ServerErrorSchema, 500: ServerErrorSchema, }, diff --git a/apps/api/app/api/v1/users/me/balance/route.ts b/apps/api/app/api/v1/users/me/balance/route.ts index 651b109a..d6bf9bea 100644 --- a/apps/api/app/api/v1/users/me/balance/route.ts +++ b/apps/api/app/api/v1/users/me/balance/route.ts @@ -21,7 +21,7 @@ export async function GET(req: Request): Promise diff --git a/apps/web/app/(app)/layout.tsx b/apps/web/app/(app)/layout.tsx index 28e0874a..86453820 100644 --- a/apps/web/app/(app)/layout.tsx +++ b/apps/web/app/(app)/layout.tsx @@ -41,7 +41,9 @@ function MainNav({ export default async function AppLayout({ children }: { children: React.ReactNode }) { let initialBalance try { - const { balance } = await getMyBalance() + const { + data: { balance }, + } = await getMyBalance() initialBalance = balance } catch (_error) { // Ignore diff --git a/apps/web/app/(app)/leaderboard/[year]/[month]/page.tsx b/apps/web/app/(app)/leaderboard/[year]/[month]/page.tsx index f8b8b995..39cf0d28 100644 --- a/apps/web/app/(app)/leaderboard/[year]/[month]/page.tsx +++ b/apps/web/app/(app)/leaderboard/[year]/[month]/page.tsx @@ -74,7 +74,7 @@ function LeaderboardUserTable({ } export default async function AppLeaderboardSearchPage({ params }: { params: { month: string; year: string } }) { - const leaderboard = await getLeaderboard({ year: params.year, month: params.month }) + const { data: leaderboard } = await getLeaderboard({ year: params.year, month: params.month }) const monthNames = [ 'January', diff --git a/apps/web/app/(app)/leaderboard/page.tsx b/apps/web/app/(app)/leaderboard/page.tsx index d342d72b..1e8d8a96 100644 --- a/apps/web/app/(app)/leaderboard/page.tsx +++ b/apps/web/app/(app)/leaderboard/page.tsx @@ -74,7 +74,7 @@ function LeaderboardUserTable({ } export default async function AppQuestionsPage() { - const leaderboard = await getLeaderboard({}) + const { data: leaderboard } = await getLeaderboard({}) const monthNames = [ 'January', diff --git a/apps/web/app/(app)/lists/[listId]/[listSlug]/page.tsx b/apps/web/app/(app)/lists/[listId]/[listSlug]/page.tsx index 2d578e79..7c4b737d 100644 --- a/apps/web/app/(app)/lists/[listId]/[listSlug]/page.tsx +++ b/apps/web/app/(app)/lists/[listId]/[listSlug]/page.tsx @@ -4,7 +4,7 @@ import { ListComments } from '@play-money/lists/components/ListComments' import { ListPage } from '@play-money/lists/components/ListPage' export default async function AppListsSlugPage({ params }: { params: { listId: string } }) { - const list = await getExtendedList({ listId: params.listId }) + const { data: list } = await getExtendedList({ listId: params.listId }) // eslint-disable-next-line @typescript-eslint/require-await -- Next requires this to be async since its SSR const handleRevalidate = async () => { diff --git a/apps/web/app/(app)/lists/[listId]/layout.tsx b/apps/web/app/(app)/lists/[listId]/layout.tsx index 5935912a..729c0bab 100644 --- a/apps/web/app/(app)/lists/[listId]/layout.tsx +++ b/apps/web/app/(app)/lists/[listId]/layout.tsx @@ -9,7 +9,7 @@ export default async function AppListsLayout({ children: React.ReactNode params: { listId: string } }) { - const list = await getExtendedList({ listId: params.listId }) + const { data: list } = await getExtendedList({ listId: params.listId }) // eslint-disable-next-line @typescript-eslint/require-await -- Next requires this to be async since its SSR const handleRevalidate = async () => { diff --git a/apps/web/app/(app)/page.tsx b/apps/web/app/(app)/page.tsx index 40c526e0..5ce5d41e 100644 --- a/apps/web/app/(app)/page.tsx +++ b/apps/web/app/(app)/page.tsx @@ -13,9 +13,9 @@ import { Button } from '@play-money/ui/button' import { Card } from '@play-money/ui/card' export default async function AppPage() { - const { markets: closingMarkets } = await getMarkets({ sortField: 'closeDate', sortDirection: 'asc', pageSize: '5' }) - const { markets: newMarkets } = await getMarkets({ pageSize: '10' }) - const { lists: newLists } = await getLists({ pageSize: '5' }) + const { data: closingMarkets } = await getMarkets({ sortField: 'closeDate', sortDirection: 'asc', limit: 5 }) + const { data: newMarkets } = await getMarkets({ limit: 10 }) + const { data: newLists } = await getLists({ limit: 5 }) return (
diff --git a/apps/web/app/(app)/questions/[marketId]/[slug]/comments/page.tsx b/apps/web/app/(app)/questions/[marketId]/[slug]/comments/page.tsx index 940a7a49..70092826 100644 --- a/apps/web/app/(app)/questions/[marketId]/[slug]/comments/page.tsx +++ b/apps/web/app/(app)/questions/[marketId]/[slug]/comments/page.tsx @@ -4,7 +4,7 @@ import { MarketComments } from '@play-money/markets/components/MarketComments' import { MarketCommentsPage } from '@play-money/markets/components/MarketCommentsPage' export default async function AppPostsSlugPage({ params }: { params: { marketId: string } }) { - const market = await getExtendedMarket({ marketId: params.marketId }) + const { data: market } = await getExtendedMarket({ marketId: params.marketId }) return } /> } diff --git a/apps/web/app/(app)/questions/[marketId]/[slug]/liquidity/page.tsx b/apps/web/app/(app)/questions/[marketId]/[slug]/liquidity/page.tsx index d1091728..06dce6fb 100644 --- a/apps/web/app/(app)/questions/[marketId]/[slug]/liquidity/page.tsx +++ b/apps/web/app/(app)/questions/[marketId]/[slug]/liquidity/page.tsx @@ -3,9 +3,9 @@ import { getExtendedMarket, getMarketLiquidityTransactions } from '@play-money/a import { MarketLiquidityPage } from '@play-money/markets/components/MarketLiquidityPage' export default async function AppPostsSlugPage({ params }: { params: { marketId: string } }) { - const market = await getExtendedMarket({ marketId: params.marketId }) - const liquidityTransactions = await getMarketLiquidityTransactions({ marketId: params.marketId }) - const userLiquidity = liquidityTransactions.transactions.filter((t) => t.initiatorId) + const { data: market } = await getExtendedMarket({ marketId: params.marketId }) + const { data: transactions, pageInfo } = await getMarketLiquidityTransactions({ marketId: params.marketId }) + const userLiquidity = transactions.filter((t) => t.initiatorId) - return + return } diff --git a/apps/web/app/(app)/questions/[marketId]/[slug]/page.tsx b/apps/web/app/(app)/questions/[marketId]/[slug]/page.tsx index 9dd40035..2b0d7d67 100644 --- a/apps/web/app/(app)/questions/[marketId]/[slug]/page.tsx +++ b/apps/web/app/(app)/questions/[marketId]/[slug]/page.tsx @@ -4,7 +4,7 @@ import { MarketActivity } from '@play-money/markets/components/MarketActivity' import { MarketOverviewPage } from '@play-money/markets/components/MarketOverviewPage' export default async function AppPostsSlugPage({ params }: { params: { marketId: string } }) { - const market = await getExtendedMarket({ marketId: params.marketId }) + const { data: market } = await getExtendedMarket({ marketId: params.marketId }) // eslint-disable-next-line @typescript-eslint/require-await -- Next requires this to be async since its SSR const handleRevalidate = async () => { diff --git a/apps/web/app/(app)/questions/[marketId]/[slug]/positions/page.tsx b/apps/web/app/(app)/questions/[marketId]/[slug]/positions/page.tsx index 9f421b9a..779a56c3 100644 --- a/apps/web/app/(app)/questions/[marketId]/[slug]/positions/page.tsx +++ b/apps/web/app/(app)/questions/[marketId]/[slug]/positions/page.tsx @@ -3,11 +3,11 @@ import { getExtendedMarket, getMarketPositions } from '@play-money/api-helpers/c import { MarketPositionsPage } from '@play-money/markets/components/MarketPositionsPage' export default async function AppPostsSlugPage({ params }: { params: { marketId: string } }) { - const market = await getExtendedMarket({ marketId: params.marketId }) - const { marketPositions } = await getMarketPositions({ + const { data: market } = await getExtendedMarket({ marketId: params.marketId }) + const { data: marketPositions } = await getMarketPositions({ marketId: params.marketId, status: 'active', - pageSize: '1000', + limit: 100, }) return diff --git a/apps/web/app/(app)/questions/[marketId]/[slug]/trades/page.tsx b/apps/web/app/(app)/questions/[marketId]/[slug]/trades/page.tsx index 466e0309..1942d72e 100644 --- a/apps/web/app/(app)/questions/[marketId]/[slug]/trades/page.tsx +++ b/apps/web/app/(app)/questions/[marketId]/[slug]/trades/page.tsx @@ -6,14 +6,14 @@ export default async function AppPostsSlugPage({ searchParams, }: { params: { marketId: string } - searchParams: { pageSize?: string; page?: string } + searchParams: { limit?: string; cursor?: string } }) { - const market = await getExtendedMarket({ marketId: params.marketId }) - const { transactions = [], totalPages } = await getMarketTransactions({ + const { data: market } = await getExtendedMarket({ marketId: params.marketId }) + const { data: transactions = [], pageInfo } = await getMarketTransactions({ marketId: params.marketId, - pageSize: searchParams.pageSize, - page: searchParams.page, + limit: searchParams.limit ? Number(searchParams.limit) : undefined, + cursor: searchParams.cursor, }) - return + return } diff --git a/apps/web/app/(app)/questions/[marketId]/layout.tsx b/apps/web/app/(app)/questions/[marketId]/layout.tsx index 425c54b2..ab45f3b9 100644 --- a/apps/web/app/(app)/questions/[marketId]/layout.tsx +++ b/apps/web/app/(app)/questions/[marketId]/layout.tsx @@ -9,7 +9,7 @@ export default async function AppQuestionsLayout({ children: React.ReactNode params: { marketId: string } }) { - const market = await getExtendedMarket({ marketId: params.marketId }) + const { data: market } = await getExtendedMarket({ marketId: params.marketId }) // eslint-disable-next-line @typescript-eslint/require-await -- Next requires this to be async since its SSR const handleRevalidate = async () => { diff --git a/apps/web/app/(app)/questions/page.tsx b/apps/web/app/(app)/questions/page.tsx index 405bf7a9..1e85d2e3 100644 --- a/apps/web/app/(app)/questions/page.tsx +++ b/apps/web/app/(app)/questions/page.tsx @@ -5,20 +5,20 @@ import { MarketsTable } from '@play-money/markets/components/MarketsTable' export default async function AppQuestionsPage({ searchParams, }: { - searchParams: { pageSize?: string; page?: string; sort?: string; status?: string; tag?: string } + searchParams: { limit?: string; cursor?: string; sort?: string; status?: string; tag?: string } }) { - const { markets, totalPages } = await getMarkets({ - pageSize: searchParams.pageSize, - page: searchParams.page, + const { data: markets, pageInfo } = await getMarkets({ + limit: searchParams.limit ? Number(searchParams.limit) : undefined, + cursor: searchParams.cursor, sortField: searchParams.sort?.split('-')[0], - sortDirection: searchParams.sort?.split('-')[1], + sortDirection: searchParams.sort?.split('-')[1] as 'asc' | 'desc', status: searchParams.status, - tag: searchParams.tag, + tags: searchParams.tag ? [searchParams.tag] : undefined, }) return (
- +
) } diff --git a/apps/web/app/(app)/questions/tagged/[tag]/page.tsx b/apps/web/app/(app)/questions/tagged/[tag]/page.tsx index 7a373504..98f9d737 100644 --- a/apps/web/app/(app)/questions/tagged/[tag]/page.tsx +++ b/apps/web/app/(app)/questions/tagged/[tag]/page.tsx @@ -3,7 +3,7 @@ import { getMarkets } from '@play-money/api-helpers/client' import { MarketList } from '@play-money/markets/components/MarketList' export default async function AppQuestionsPage({ params }: { params: { tag: string } }) { - const { markets } = await getMarkets({ tag: params.tag }) + const { data: markets } = await getMarkets({ tags: [params.tag] }) return (
diff --git a/apps/web/app/(app)/settings/api/page.tsx b/apps/web/app/(app)/settings/api/page.tsx index 6504c1a5..9f7f8677 100644 --- a/apps/web/app/(app)/settings/api/page.tsx +++ b/apps/web/app/(app)/settings/api/page.tsx @@ -12,7 +12,7 @@ export default async function AppSettingsPage() { redirect('/login?redirect=/settings/api') } - const { keys } = await getMyApiKeys() + const { data: keys } = await getMyApiKeys() async function handleCreateKey() { 'use server' diff --git a/apps/web/app/(app)/settings/referrals/page.tsx b/apps/web/app/(app)/settings/referrals/page.tsx index 87e7936f..52987b3f 100644 --- a/apps/web/app/(app)/settings/referrals/page.tsx +++ b/apps/web/app/(app)/settings/referrals/page.tsx @@ -11,7 +11,7 @@ export default async function AppSettingsPage() { redirect('/login?redirect=/settings/referrals') } - const { referrals } = await getMyReferrals() + const { data: referrals } = await getMyReferrals() return } diff --git a/apps/web/app/(app)/setup/page.tsx b/apps/web/app/(app)/setup/page.tsx index b1d290cc..5637c2ec 100644 --- a/apps/web/app/(app)/setup/page.tsx +++ b/apps/web/app/(app)/setup/page.tsx @@ -21,7 +21,7 @@ export default function AppSetupPage() { if (user && !user.referredBy && referringUser?.id) { try { - const updatedUser = await updateMe({ referredBy: referringUser.id }) + const { data: updatedUser } = await updateMe({ referredBy: referringUser.id }) setUser(updatedUser) clear() diff --git a/packages/api-helpers/client/hooks.ts b/packages/api-helpers/client/hooks.ts index e9123017..8e3efecf 100644 --- a/packages/api-helpers/client/hooks.ts +++ b/packages/api-helpers/client/hooks.ts @@ -12,21 +12,14 @@ const SIXTY_SECONDS = 1000 * 60 const FIVE_MINUTES = SIXTY_SECONDS * 5 const ONE_HOUR = SIXTY_SECONDS * 60 -export function useLiquidity() { - return useSWR<{ transactions: Array }>(`/v1/liquidity`, { +export function useRecentTrades() { + return useSWR<{ data: Array }>(`/v1/transactions?transactionType=TRADE_BUY,TRADE_SELL`, { refreshInterval: FIVE_MINUTES, }) } -export function useRecentTrades() { - return useSWR<{ transactions: Array }>( - `/v1/transactions?transactionType=TRADE_BUY,TRADE_SELL`, - { refreshInterval: FIVE_MINUTES } - ) -} - export function useSiteActivity() { - return useSWR<{ activities: Array }>(`/v1/activity`, { refreshInterval: FIVE_MINUTES }) + return useSWR<{ data: Array }>(`/v1/activity`, { refreshInterval: FIVE_MINUTES }) } export function MARKET_BALANCE_PATH(marketId: string) { @@ -34,9 +27,11 @@ export function MARKET_BALANCE_PATH(marketId: string) { } export function useMarketBalance({ marketId }: { marketId: string }) { return useSWR<{ - amm: Array - user: Array - userPositions: Array + data: { + amm: Array + user: Array + userPositions: Array + } }>(MARKET_BALANCE_PATH(marketId), { refreshInterval: SIXTY_SECONDS, }) @@ -47,18 +42,22 @@ export function LIST_BALANCE_PATH(listId: string) { } export function useListBalance({ listId }: { listId: string }) { return useSWR<{ - user: Array - userPositions: Array + data: { + user: Array + userPositions: Array + } }>(LIST_BALANCE_PATH(listId), { refreshInterval: SIXTY_SECONDS, }) } -export function useMarketPositions({ marketId }: { marketId: string }) { +export function useMarketBalances({ marketId }: { marketId: string }) { return useSWR<{ - balances: Array - user: NetBalanceAsNumbers & { account: { userPrimary: User } } - }>(`/v1/markets/${marketId}/positions`) + data: { + balances: Array + user: NetBalanceAsNumbers & { account: { userPrimary: User } } + } + }>(`/v1/markets/${marketId}/balances`) } export function MARKET_GRAPH_PATH(marketId: string) { @@ -79,25 +78,25 @@ export function useMarketGraph({ marketId }: { marketId: string }) { export function useMarketRelated({ marketId }: { marketId: string }) { return useSWR<{ - markets: Array + data: Array }>(`/v1/markets/${marketId}/related`) } export const MY_NOTIFICATIONS_PATH = '/v1/users/me/notifications' export function useNotifications({ skip = false }: { skip?: boolean }) { - return useSWR<{ unreadCount: number; notifications: Array }>( + return useSWR<{ data: { unreadCount: number; notifications: Array } }>( !skip ? MY_NOTIFICATIONS_PATH : null, { refreshInterval: FIVE_MINUTES } ) } export function useUserStats({ userId, skip = false }: { userId: string; skip?: boolean }) { - return useSWR<{ quests: Array }>(!skip ? `/v1/users/${userId}/stats` : null) + return useSWR<{ data: { quests: Array } }>(!skip ? `/v1/users/${userId}/stats` : null) } export const MY_BALANCE_PATH = '/v1/users/me/balance' export function useMyBalance({ skip = false }: { skip?: boolean }) { - return useSWR<{ balance: number }>(!skip ? '/v1/users/me/balance' : null) + return useSWR<{ data: { balance: number } }>(!skip ? '/v1/users/me/balance' : null) } export function useUserGraph({ userId }: { userId: string }) { diff --git a/packages/api-helpers/client/index.ts b/packages/api-helpers/client/index.ts index 62089b0c..baa7c80d 100644 --- a/packages/api-helpers/client/index.ts +++ b/packages/api-helpers/client/index.ts @@ -5,6 +5,7 @@ import { NetBalanceAsNumbers } from '@play-money/finance/lib/getBalances' import { TransactionWithEntries, LeaderboardUser, ExtendedMarketOptionPosition } from '@play-money/finance/types' import { ExtendedList } from '@play-money/lists/types' import { ExtendedMarket, ExtendedMarketPosition, MarketActivity } from '@play-money/markets/types' +import { PaginatedResponse, PaginationRequest } from '../types' // TODO: @casesandberg Generate this from OpenAPI schema @@ -28,53 +29,62 @@ async function apiHandler( next: options?.next, ...creds, } as RequestInit) + if (!res.ok || res.status >= 400) { const { error } = (await res.json()) as { error: string } throw new Error(error || 'There was an error with this request') } + if (res.status === 204) { + throw new Error('deleted') + } + return res.json() as Promise } export async function getMarketTransactions({ marketId, - page, - pageSize, + ...paginationParams }: { marketId: string - page?: string - pageSize?: string -}) { - return apiHandler<{ - transactions: Array - page: number - pageSize: number - totalPages: number - }>( - `${process.env.NEXT_PUBLIC_API_URL}/v1/transactions?marketId=${marketId}&transactionType=TRADE_BUY,TRADE_SELL${ - page ? `&page=${page}` : '' - }${pageSize ? `&pageSize=${pageSize}` : ''}` +} & PaginationRequest) { + const currentParams = new URLSearchParams( + JSON.parse( + JSON.stringify({ + marketId, + transactionType: ['TRADE_BUY', 'TRADE_SELL'], + ...paginationParams, + }) + ) + ) + + const search = currentParams.toString() + + return apiHandler>( + `${process.env.NEXT_PUBLIC_API_URL}/v1/transactions${search ? `?${search}` : ''}` ) } export async function getMarketLiquidityTransactions({ marketId, - page, - pageSize, + ...paginationParams }: { marketId: string - page?: string - pageSize?: string -}) { - return apiHandler<{ - transactions: Array - page: number - pageSize: number - totalPages: number - }>( - `${process.env.NEXT_PUBLIC_API_URL}/v1/transactions?marketId=${marketId}&transactionType=LIQUIDITY_INITIALIZE,LIQUIDITY_DEPOSIT,LIQUIDITY_WITHDRAWAL${ - page ? `&page=${page}` : '' - }${pageSize ? `&pageSize=${pageSize}` : ''}` +} & PaginationRequest) { + const currentParams = new URLSearchParams( + JSON.parse( + JSON.stringify({ + marketId, + transactionType: ['LIQUIDITY_INITIALIZE', 'LIQUIDITY_DEPOSIT', 'LIQUIDITY_WITHDRAWAL'], + ...paginationParams, + }) + ) + ) + + const search = currentParams.toString() + + return apiHandler>( + `${process.env.NEXT_PUBLIC_API_URL}/v1/transactions${search ? `?${search}` : ''}` ) } @@ -124,133 +134,117 @@ export async function deleteComment({ commentId }: { commentId: string }) { } export async function getMyBalance() { - return apiHandler<{ balance: number }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/me/balance`) + return apiHandler<{ data: { balance: number } }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/me/balance`) } export async function getMyReferrals() { - return apiHandler<{ referrals: Array }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/me/referrals`) + return apiHandler<{ data: Array }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/me/referrals`) } export async function getMarkets({ - tag, - page, - pageSize, status, - sortField, - sortDirection, + createdBy, + tags, + ...paginationParams }: { - tag?: string - page?: string - pageSize?: string status?: string - sortField?: string - sortDirection?: string -} = {}) { + createdBy?: string + tags?: Array +} & PaginationRequest = {}) { const currentParams = new URLSearchParams( - JSON.parse(JSON.stringify({ tag, page, pageSize, status, sortField, sortDirection })) + JSON.parse(JSON.stringify({ status, createdBy, tags, ...paginationParams })) ) + const search = currentParams.toString() - return apiHandler<{ - markets: Array - page: number - pageSize: number - totalPages: number - }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/markets${search ? `?${search}` : ''}`, { - next: { tags: ['markets'] }, - }) + return apiHandler>( + `${process.env.NEXT_PUBLIC_API_URL}/v1/markets${search ? `?${search}` : ''}`, + { + next: { tags: ['markets'] }, + } + ) } export async function getMarketPositions({ ownerId, marketId, - page, - pageSize, status, - sortField, - sortDirection, + ...paginationParams }: { ownerId?: string marketId?: string - page?: string - pageSize?: string status?: 'active' | 'closed' | 'all' - sortField?: string - sortDirection?: string -} = {}) { +} & PaginationRequest = {}): Promise> { const currentParams = new URLSearchParams( - JSON.parse(JSON.stringify({ ownerId, page, pageSize, status, sortField, sortDirection, marketId })) + JSON.parse( + JSON.stringify({ + ownerId, + status, + ...paginationParams, + }) + ) ) const search = currentParams.toString() - return apiHandler<{ - marketPositions: Array - page: number - pageSize: number - totalPages: number - }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/market-positions${search ? `?${search}` : ''}`, { - next: { tags: ['markets'] }, - }) + return apiHandler>( + `${process.env.NEXT_PUBLIC_API_URL}/v1/markets/${marketId}/positions${search ? `?${search}` : ''}`, + { + next: { tags: ['markets'] }, + } + ) } export async function getLists({ - tag, - page, - pageSize, - status, - sortField, - sortDirection, + ownerId, + ...paginationParams }: { - tag?: string - page?: string - pageSize?: string - status?: string - sortField?: string - sortDirection?: string -} = {}) { - const currentParams = new URLSearchParams( - JSON.parse(JSON.stringify({ tag, page, pageSize, status, sortField, sortDirection })) - ) + ownerId?: string +} & PaginationRequest = {}): Promise> { + const currentParams = new URLSearchParams(JSON.parse(JSON.stringify({ ownerId, ...paginationParams }))) const search = currentParams.toString() - return apiHandler<{ - lists: Array - page: number - pageSize: number - totalPages: number - }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/lists${search ? `?${search}` : ''}`, { - next: { tags: ['lists'] }, - }) + return apiHandler>( + `${process.env.NEXT_PUBLIC_API_URL}/v1/lists${search ? `?${search}` : ''}`, + { + next: { tags: ['lists'] }, + } + ) } export async function getExtendedMarket({ marketId }: { marketId: string }) { - return apiHandler(`${process.env.NEXT_PUBLIC_API_URL}/v1/markets/${marketId}?extended=true`, { - next: { tags: [`market:${marketId}`] }, - }) + return apiHandler<{ data: ExtendedMarket }>( + `${process.env.NEXT_PUBLIC_API_URL}/v1/markets/${marketId}?extended=true`, + { + next: { tags: [`market:${marketId}`] }, + } + ) } export async function getExtendedList({ listId }: { listId: string }) { - return apiHandler(`${process.env.NEXT_PUBLIC_API_URL}/v1/lists/${listId}?extended=true`, { + return apiHandler<{ data: ExtendedList }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/lists/${listId}?extended=true`, { next: { tags: [`list:${listId}`] }, }) } export async function createMarket(body: Record) { - return apiHandler<{ market?: Market; list?: List }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/markets`, { + return apiHandler<{ data: { market?: Market; list?: List } }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/markets`, { method: 'POST', body, }) } export async function createListMarket({ listId }: { listId: string }, body: Record) { - return apiHandler<{ market?: Market; list?: List }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/lists/${listId}/markets`, { - method: 'POST', - body, - }) + return apiHandler<{ data: { market?: Market; list?: List } }>( + `${process.env.NEXT_PUBLIC_API_URL}/v1/lists/${listId}/markets`, + { + method: 'POST', + body, + } + ) } export async function updateMarket({ marketId, body }: { marketId: string; body: Record }) { - return apiHandler(`${process.env.NEXT_PUBLIC_API_URL}/v1/markets/${marketId}`, { + return apiHandler<{ data: Market }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/markets/${marketId}`, { method: 'PATCH', body: body, }) @@ -265,7 +259,7 @@ export async function updateMarketOption({ optionId: string body: Record }) { - return apiHandler(`${process.env.NEXT_PUBLIC_API_URL}/v1/markets/${marketId}/options/${optionId}`, { + return apiHandler<{ data: Market }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/markets/${marketId}/options/${optionId}`, { method: 'PATCH', body: body, }) @@ -327,7 +321,7 @@ export async function getMarketQuote({ amount: number isBuy?: boolean }) { - return apiHandler<{ newProbability: number; potentialReturn: number }>( + return apiHandler<{ data: { newProbability: number; potentialReturn: number } }>( `${process.env.NEXT_PUBLIC_API_URL}/v1/markets/${marketId}/quote`, { method: 'POST', @@ -344,8 +338,8 @@ export async function getMarketComments({ marketId, }: { marketId: string -}): Promise<{ comments: Array }> { - return apiHandler<{ comments: Array }>( +}): Promise<{ data: Array }> { + return apiHandler<{ data: Array }>( `${process.env.NEXT_PUBLIC_API_URL}/v1/markets/${marketId}/comments`, { next: { tags: [`${marketId}:comments`] }, @@ -353,12 +347,8 @@ export async function getMarketComments({ ) } -export async function getMarketActivity({ - marketId, -}: { - marketId: string -}): Promise<{ activities: Array }> { - return apiHandler<{ activities: Array }>( +export async function getMarketActivity({ marketId }: { marketId: string }): Promise<{ data: Array }> { + return apiHandler<{ data: Array }>( `${process.env.NEXT_PUBLIC_API_URL}/v1/markets/${marketId}/activity`, { next: { tags: [`${marketId}:activity`] }, @@ -366,12 +356,8 @@ export async function getMarketActivity({ ) } -export async function getListComments({ - listId, -}: { - listId: string -}): Promise<{ comments: Array }> { - return apiHandler<{ comments: Array }>( +export async function getListComments({ listId }: { listId: string }): Promise<{ data: Array }> { + return apiHandler<{ data: Array }>( `${process.env.NEXT_PUBLIC_API_URL}/v1/lists/${listId}/comments`, { next: { tags: [`list:${listId}:comments`] }, @@ -430,7 +416,7 @@ export async function createMyResourceViewed({ } export async function getSearch({ query }: { query: string }) { - return apiHandler<{ users: Array; markets: Array; lists: Array }>( + return apiHandler<{ data: { users: Array; markets: Array; lists: Array } }>( `${process.env.NEXT_PUBLIC_API_URL}/v1/search?query=${query}` ) } @@ -439,14 +425,14 @@ export async function getUserCheckUsername({ username, }: { username: string -}): Promise<{ available: boolean; message?: string }> { - return apiHandler<{ available: boolean; message?: string }>( +}): Promise<{ data: { available: boolean; message?: string } }> { + return apiHandler<{ data: { available: boolean; message?: string } }>( `${process.env.NEXT_PUBLIC_API_URL}/v1/users/check-username?username=${encodeURIComponent(username)}` ) } export async function updateMe(data: Record) { - return apiHandler(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/me`, { + return apiHandler<{ data: User }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/me`, { method: 'PATCH', body: data, }) @@ -454,43 +440,41 @@ export async function updateMe(data: Record) { export async function getUserStats({ userId }: { userId: string }) { return apiHandler<{ - netWorth: number - tradingVolume: number - totalMarkets: number - lastTradeAt: Date - activeDayCount: number - otherIncome: number - quests: Array<{ - title: string - award: number - completed: boolean - href: string - }> + data: { + netWorth: number + tradingVolume: number + totalMarkets: number + lastTradeAt: Date + activeDayCount: number + otherIncome: number + quests: Array<{ + title: string + award: number + completed: boolean + href: string + }> + } }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/${userId}/stats`) } -export async function getUser({ userId }: { userId: string }): Promise { - return apiHandler(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/${userId}`) +export async function getUser({ userId }: { userId: string }): Promise<{ data: User }> { + return apiHandler<{ data: User }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/${userId}`) } -export async function getUserReferral({ code }: { code: string }): Promise { - return apiHandler(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/referral/${code}`) +export async function getUserReferral({ code }: { code: string }): Promise<{ data: User }> { + return apiHandler<{ data: User }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/referral/${code}`) } -export async function getUserUsername({ username }: { username: string }): Promise { - return apiHandler(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/username/${username}`, { +export async function getUserUsername({ username }: { username: string }): Promise<{ data: User }> { + return apiHandler<{ data: User }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/username/${username}`, { next: { revalidate: 0, // Equivalent to `cache: 'no-store'` in Next.js for disabling caching }, }) } -export async function getUserTransactions({ - userId, -}: { - userId: string -}): Promise<{ transactions: Array }> { - return apiHandler<{ transactions: Array }>( +export async function getUserTransactions({ userId }: { userId: string }) { + return apiHandler>( `${process.env.NEXT_PUBLIC_API_URL}/v1/users/${userId}/transactions` ) } @@ -501,28 +485,30 @@ export async function getUserPositions({ }: { userId: string pageSize?: number -}): Promise<{ positions: Array }> { - return apiHandler<{ positions: Array }>( +}): Promise<{ data: { positions: Array } }> { + return apiHandler<{ data: { positions: Array } }>( `${process.env.NEXT_PUBLIC_API_URL}/v1/users/${userId}/positions${pageSize ? `?pageSize=${pageSize}` : ''}` ) } -export async function getUserBalance({ userId }: { userId: string }): Promise<{ balance: NetBalanceAsNumbers }> { - return apiHandler<{ balance: NetBalanceAsNumbers }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/${userId}/balance`) +export async function getUserBalance({ + userId, +}: { + userId: string +}): Promise<{ data: { balance: NetBalanceAsNumbers } }> { + return apiHandler<{ data: { balance: NetBalanceAsNumbers } }>( + `${process.env.NEXT_PUBLIC_API_URL}/v1/users/${userId}/balance` + ) } -export async function getUserMarkets({ userId }: { userId: string }): Promise<{ markets: Array }> { - return apiHandler<{ markets: Array }>( +export async function getUserMarkets({ userId }: { userId: string }): Promise> { + return apiHandler>( `${process.env.NEXT_PUBLIC_API_URL}/v1/markets?createdBy=${userId}` ) } -export async function getUserLists({ userId }: { userId: string }): Promise<{ lists: Array }> { - return apiHandler<{ lists: Array }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/lists?ownerId=${userId}`) -} - export async function createMarketGenerateTags({ question }: { question: string }) { - return apiHandler<{ tags: Array }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/markets/generate-tags`, { + return apiHandler<{ data: Array }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/markets/generate-tags`, { method: 'POST', body: { question, @@ -532,23 +518,25 @@ export async function createMarketGenerateTags({ question }: { question: string export async function getLeaderboard({ month, year }: { month?: string; year?: string }) { return apiHandler<{ - topTraders: Array - topCreators: Array - topPromoters: Array - topQuesters: Array - topReferrers: Array - userRankings?: { - trader: LeaderboardUser - creator: LeaderboardUser - promoter: LeaderboardUser - quester: LeaderboardUser - referrer: LeaderboardUser + data: { + topTraders: Array + topCreators: Array + topPromoters: Array + topQuesters: Array + topReferrers: Array + userRankings?: { + trader: LeaderboardUser + creator: LeaderboardUser + promoter: LeaderboardUser + quester: LeaderboardUser + referrer: LeaderboardUser + } } }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/leaderboard${month && year ? `?year=${year}&month=${month}` : ''}`) } -export async function createMyApiKey({ name }: { name: string }): Promise { - return apiHandler(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/me/api-keys`, { +export async function createMyApiKey({ name }: { name: string }): Promise<{ data: ApiKey }> { + return apiHandler<{ data: ApiKey }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/me/api-keys`, { method: 'POST', body: { name, @@ -556,6 +544,6 @@ export async function createMyApiKey({ name }: { name: string }): Promise }> { - return apiHandler<{ keys: Array }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/me/api-keys`) +export async function getMyApiKeys(): Promise<{ data: Array }> { + return apiHandler<{ data: Array }>(`${process.env.NEXT_PUBLIC_API_URL}/v1/users/me/api-keys`) } diff --git a/packages/api-helpers/index.ts b/packages/api-helpers/index.ts index 7a92441b..6d9816d3 100644 --- a/packages/api-helpers/index.ts +++ b/packages/api-helpers/index.ts @@ -2,3 +2,5 @@ export * from './lib/createSchema' export * from './lib/formatZodError' export * from './lib/ServerError' export * from './lib/helpers' +export * from './lib/pagination' +export * from './types' diff --git a/packages/api-helpers/lib/createSchema.ts b/packages/api-helpers/lib/createSchema.ts index d8713a32..ebc61d2d 100644 --- a/packages/api-helpers/lib/createSchema.ts +++ b/packages/api-helpers/lib/createSchema.ts @@ -7,16 +7,27 @@ interface EndpointDefinition { parameters?: z.ZodObject | z.ZodOptional> requestBody?: z.ZodObject responses: { - [statusCode: number]: z.ZodObject | z.ZodObject[] + [statusCode: number]: z.ZodObject | z.ZodObject[] | z.ZodVoid } + security?: boolean + summary?: string + private?: boolean // Internal or half-baked endpoints } type InferZodResponse = - T extends z.ZodObject ? z.infer : T extends z.ZodObject[] ? z.infer : never + T extends z.ZodObject + ? z.infer + : T extends z.ZodObject[] + ? z.infer + : T extends z.ZodVoid + ? void + : never -type InferResponses | z.ZodObject[] }> = InferZodResponse +type InferResponses | z.ZodObject[] | z.ZodVoid }> = InferZodResponse< + T[keyof T] +> -export type SchemaResponse | z.ZodObject[] }> = Promise< +export type SchemaResponse | z.ZodObject[] | z.ZodVoid }> = Promise< NextResponse> > diff --git a/packages/api-helpers/lib/helpers.ts b/packages/api-helpers/lib/helpers.ts index bf1b2a73..b931d8b0 100644 --- a/packages/api-helpers/lib/helpers.ts +++ b/packages/api-helpers/lib/helpers.ts @@ -1,3 +1,5 @@ +import { z } from 'zod' + export function stripUndefined>( obj: T ): { [K in keyof T]: Exclude } { @@ -5,3 +7,8 @@ export function stripUndefined>( [K in keyof T]: Exclude } } + +export const zodCoerceCSVToArray = z.preprocess( + (val) => (typeof val === 'string' ? val.split(',') : val), + z.array(z.string()) +) diff --git a/packages/api-helpers/lib/pagination.ts b/packages/api-helpers/lib/pagination.ts new file mode 100644 index 00000000..49670b5c --- /dev/null +++ b/packages/api-helpers/lib/pagination.ts @@ -0,0 +1,104 @@ +import { Prisma } from '@prisma/client' +import { z } from 'zod' +import db from '@play-money/database' +import { PaginationRequest, PaginatedResponse } from '../types' + +const MAX_LIMIT = 100 +const DEFAULT_LIMIT = 50 + +export function validatePaginationParams(params: PaginationRequest) { + return { + cursor: params.cursor, + limit: Math.min(params.limit ?? DEFAULT_LIMIT, MAX_LIMIT), + sortDirection: params.sortDirection ?? 'desc', + sortField: params.sortField, + } +} + +export async function getPaginatedItems(data: { + model: typeof db.market + pagination: PaginationRequest + where?: Prisma.MarketWhereInput + include?: Prisma.MarketInclude + orderBy?: Prisma.MarketOrderByWithRelationInput +}): Promise> +export async function getPaginatedItems(data: { + model: typeof db.list + pagination: PaginationRequest + where?: Prisma.ListWhereInput + include?: Prisma.ListInclude + orderBy?: Prisma.ListOrderByWithRelationInput +}): Promise> +export async function getPaginatedItems(data: { + model: typeof db.marketOptionPosition + pagination: PaginationRequest + where?: Prisma.MarketOptionPositionWhereInput + include?: Prisma.MarketOptionPositionInclude + orderBy?: Prisma.MarketOptionPositionOrderByWithRelationInput +}): Promise> +export async function getPaginatedItems(data: { + model: typeof db.transaction + pagination: PaginationRequest + where?: Prisma.TransactionWhereInput + include?: Prisma.TransactionInclude + orderBy?: Prisma.TransactionOrderByWithRelationInput +}): Promise> +export async function getPaginatedItems({ + model, + pagination, + where = {}, + include = {}, + orderBy = {}, +}: { + model: any + pagination: PaginationRequest + where?: any + include?: any + orderBy?: any +}): Promise> { + const { cursor, limit, sortField, sortDirection } = validatePaginationParams(pagination) + + const cursorCondition = cursor + ? { + cursor: { + id: cursor, + }, + skip: 1, // Skip the cursor + } + : {} + + const orderCondition = sortField ? { [sortField]: sortDirection } : { createdAt: sortDirection } + + const [items, total] = await Promise.all([ + model.findMany({ + where, + include, + orderBy: { ...orderCondition, ...orderBy }, + ...cursorCondition, + take: limit + 1, + }), + model.count({ where }), + ]) + + const hasNextPage = items.length > limit + const data = hasNextPage ? items.slice(0, -1) : items + + return { + data, + pageInfo: { + hasNextPage, + endCursor: data[data.length - 1]?.id, + total, + }, + } +} + +export const createPaginatedResponseSchema = (itemSchema: T) => + z.object({ + data: z.array(itemSchema), + pageInfo: z.object({ + hasNextPage: z.boolean(), + endCursor: z.string().optional(), + total: z.number(), + }), + }) diff --git a/packages/api-helpers/types.ts b/packages/api-helpers/types.ts new file mode 100644 index 00000000..b3c1a459 --- /dev/null +++ b/packages/api-helpers/types.ts @@ -0,0 +1,20 @@ +import { z } from 'zod' + +export const paginationSchema = z.object({ + cursor: z.string().optional(), + limit: z.coerce.number().min(1).max(100).optional(), + sortField: z.string().optional(), + sortDirection: z.enum(['asc', 'desc']).optional(), +}) + +export type PaginationRequest = z.infer & { sortDirection?: 'asc' | 'desc' } +export type PageInfo = { + hasNextPage: boolean + endCursor?: string + total: number +} + +export interface PaginatedResponse { + data: T[] + pageInfo: PageInfo +} diff --git a/packages/comments/components/CommentItemCard.tsx b/packages/comments/components/CommentItemCard.tsx index 99d95b49..1ceb479a 100644 --- a/packages/comments/components/CommentItemCard.tsx +++ b/packages/comments/components/CommentItemCard.tsx @@ -36,7 +36,13 @@ export function CommentItemCard({ }, []) const handleToggleEmojiReaction = (commentId: string) => async (emoji: string) => { - await createCommentReaction({ commentId, emoji }) + try { + await createCommentReaction({ commentId, emoji }) + } catch (error) { + if (error instanceof Error && error.message !== 'deleted') { + throw error + } + } onRevalidate() } @@ -58,7 +64,13 @@ export function CommentItemCard({ } const handleDelete = (commentId: string) => async () => { - await deleteComment({ commentId }) + try { + await deleteComment({ commentId }) + } catch (error) { + if (error instanceof Error && error.message !== 'deleted') { + throw error + } + } onRevalidate() } diff --git a/packages/comments/components/CommentsList.tsx b/packages/comments/components/CommentsList.tsx index 854c6d85..da3d2156 100644 --- a/packages/comments/components/CommentsList.tsx +++ b/packages/comments/components/CommentsList.tsx @@ -39,7 +39,13 @@ export function CommentsList({ }, []) const handleToggleEmojiReaction = (commentId: string) => async (emoji: string) => { - await createCommentReaction({ commentId, emoji }) + try { + await createCommentReaction({ commentId, emoji }) + } catch (error) { + if (error instanceof Error && error.message !== 'deleted') { + throw error + } + } onRevalidate() } @@ -61,7 +67,13 @@ export function CommentsList({ } const handleDelete = (commentId: string) => async () => { - await deleteComment({ commentId }) + try { + await deleteComment({ commentId }) + } catch (error) { + if (error instanceof Error && error.message !== 'deleted') { + throw error + } + } onRevalidate() } diff --git a/packages/comments/components/EditorExtensions.tsx b/packages/comments/components/EditorExtensions.tsx index b62bb541..52324a41 100644 --- a/packages/comments/components/EditorExtensions.tsx +++ b/packages/comments/components/EditorExtensions.tsx @@ -21,7 +21,7 @@ import { MentionList } from './MentionList' const suggestion: Omit, 'editor'> = { items: async ({ query }) => { - const data = await getSearch({ query }) + const { data } = await getSearch({ query }) return data.users }, @@ -86,7 +86,7 @@ export function MentionChip(props: NodeViewProps) { const [user, setUser] = useState() useEffect(() => { async function fetchUser() { - const user = await getUser({ userId: props.node.attrs.id }) + const { data: user } = await getUser({ userId: props.node.attrs.id }) setUser(user) } diff --git a/packages/finance/components/LiquidityTable.tsx b/packages/finance/components/LiquidityTable.tsx index 1426827e..e4093ad1 100644 --- a/packages/finance/components/LiquidityTable.tsx +++ b/packages/finance/components/LiquidityTable.tsx @@ -3,6 +3,7 @@ import { ColumnDef } from '@tanstack/react-table' import _ from 'lodash' import React from 'react' +import { PageInfo } from '@play-money/api-helpers' import { User } from '@play-money/database' import { CurrencyDisplay } from '@play-money/finance/components/CurrencyDisplay' import { formatDistanceToNowShort } from '@play-money/ui' @@ -62,6 +63,6 @@ export const columns: Array> = [ }, ] -export function LiquidityTable({ data, totalPages }: { data: Array; totalPages: number }) { - return +export function LiquidityTable({ data, pageInfo }: { data: Array; pageInfo: PageInfo }) { + return } diff --git a/packages/finance/components/RecentLiquidity.tsx b/packages/finance/components/RecentLiquidity.tsx deleted file mode 100644 index 29e83f8f..00000000 --- a/packages/finance/components/RecentLiquidity.tsx +++ /dev/null @@ -1,58 +0,0 @@ -'use client' - -import _ from 'lodash' -import Link from 'next/link' -import React from 'react' -import { useLiquidity } from '@play-money/api-helpers/client/hooks' -import { CurrencyDisplay } from '@play-money/finance/components/CurrencyDisplay' -import { formatDistanceToNowShort } from '@play-money/ui' -import { UserLink } from '@play-money/users/components/UserLink' -import { calculateBalanceChanges, findBalanceChange } from '../lib/helpers' - -export function RecentLiquidity() { - const { data } = useLiquidity() - - return ( -
    - {_.take(data?.transactions, 5).map((transaction) => { - if (!transaction.initiator) { - return null - } - const balanceChanges = calculateBalanceChanges(transaction) - const primaryChange = findBalanceChange({ - balanceChanges, - accountId: transaction.initiator.primaryAccountId, - assetType: 'CURRENCY', - assetId: 'PRIMARY', - }) - - return ( -
  • - - - - added to - {transaction.market ? ( - - - {_.truncate(transaction.market.question, { length: 60 })} - - - ) : null} - by - {transaction.initiator ? ( -
    - -
    - ) : null} - {formatDistanceToNowShort(transaction.createdAt)} -
  • - ) - })} -
- ) -} diff --git a/packages/finance/components/RecentTrades.tsx b/packages/finance/components/RecentTrades.tsx index 11f78e14..9dd21786 100644 --- a/packages/finance/components/RecentTrades.tsx +++ b/packages/finance/components/RecentTrades.tsx @@ -9,11 +9,12 @@ import { formatDistanceToNowShort } from '@play-money/ui' import { UserLink } from '@play-money/users/components/UserLink' export function RecentTrades() { - const { data } = useRecentTrades() + const { data: transactionsData } = useRecentTrades() + const transactions = transactionsData?.data return (
    - {_.take(data?.transactions, 5).map((transaction) => { + {_.take(transactions, 5).map((transaction) => { if (!transaction.initiator) { return null } diff --git a/packages/finance/components/SiteActivity.tsx b/packages/finance/components/SiteActivity.tsx index 69926f46..b83a8de8 100644 --- a/packages/finance/components/SiteActivity.tsx +++ b/packages/finance/components/SiteActivity.tsx @@ -28,7 +28,7 @@ function summarizeTransactions(transactions: Array) { export function SiteActivity() { const { data } = useSiteActivity() - const { activities = [] } = data || {} + const { data: activities = [] } = data || {} return (
    diff --git a/packages/finance/components/TradesTable.tsx b/packages/finance/components/TradesTable.tsx index 4cbdd046..48661c54 100644 --- a/packages/finance/components/TradesTable.tsx +++ b/packages/finance/components/TradesTable.tsx @@ -2,6 +2,7 @@ import { ColumnDef } from '@tanstack/react-table' import _ from 'lodash' +import { PageInfo } from '@play-money/api-helpers' import { User } from '@play-money/database' import { CurrencyDisplay } from '@play-money/finance/components/CurrencyDisplay' import { formatDistanceToNowShort } from '@play-money/ui' @@ -64,6 +65,6 @@ export const columns: Array> = [ }, ] -export function TradesTable({ data, totalPages }: { data: Array; totalPages: number }) { - return +export function TradesTable({ data, pageInfo }: { data: Array; pageInfo: PageInfo }) { + return } diff --git a/packages/finance/lib/getTransactions.ts b/packages/finance/lib/getTransactions.ts index 014cb0ef..4f6e5ce7 100644 --- a/packages/finance/lib/getTransactions.ts +++ b/packages/finance/lib/getTransactions.ts @@ -1,3 +1,4 @@ +import { getPaginatedItems, PaginationRequest } from '@play-money/api-helpers' import db from '@play-money/database' import { TransactionTypeType } from '@play-money/database/zod/inputTypeSchemas/TransactionTypeSchema' import { TransactionWithEntries } from '../types' @@ -9,51 +10,21 @@ interface TransactionFilterOptions { isReverse?: boolean | null } -interface SortOptions { - field: string - direction: 'asc' | 'desc' -} - -interface PaginationOptions { - skip: number - take: number -} - -export async function getTransactions( - filters: TransactionFilterOptions = {}, - sort: SortOptions = { field: 'createdAt', direction: 'desc' }, - pagination: PaginationOptions = { skip: 0, take: 10 } -): Promise<{ transactions: Array; total: number }> { - const [transactions, total] = await Promise.all([ - db.transaction.findMany({ - where: { - marketId: filters.marketId, - initiatorId: filters.userId, - type: filters.transactionType ? { in: filters.transactionType } : undefined, - isReverse: filters.isReverse, - }, - include: { - entries: true, - market: true, - initiator: true, - options: true, - }, - orderBy: { - [sort.field]: sort.direction, - }, - skip: pagination.skip, - take: pagination.take, - }), - - db.transaction.count({ - where: { - marketId: filters.marketId, - initiatorId: filters.userId, - type: filters.transactionType ? { in: filters.transactionType } : undefined, - isReverse: filters.isReverse, - }, - }), - ]) - - return { transactions, total } +export async function getTransactions(filters: TransactionFilterOptions = {}, pagination?: PaginationRequest) { + return getPaginatedItems({ + model: db.transaction, + pagination: pagination ?? {}, + where: { + marketId: filters.marketId, + initiatorId: filters.userId, + type: filters.transactionType ? { in: filters.transactionType } : undefined, + isReverse: filters.isReverse, + }, + include: { + entries: true, + market: true, + initiator: true, + options: true, + }, + }) } diff --git a/packages/lists/components/ListComments.tsx b/packages/lists/components/ListComments.tsx index 6084bc82..06a18076 100644 --- a/packages/lists/components/ListComments.tsx +++ b/packages/lists/components/ListComments.tsx @@ -4,7 +4,7 @@ import { getListComments } from '@play-money/api-helpers/client' import { CommentsList } from '@play-money/comments/components/CommentsList' export async function ListComments({ listId }: { listId: string }) { - const { comments } = await getListComments({ listId }) + const { data: comments } = await getListComments({ listId }) const handleRevalidate = async () => { 'use server' diff --git a/packages/lists/components/ListTradePanel.tsx b/packages/lists/components/ListTradePanel.tsx index 8205960c..ae1d6155 100644 --- a/packages/lists/components/ListTradePanel.tsx +++ b/packages/lists/components/ListTradePanel.tsx @@ -20,7 +20,8 @@ import { ExtendedList } from '../types' export function ListTradePanel({ list, onTradeComplete }: { list: ExtendedList; onTradeComplete?: () => void }) { const { selected, setSelected } = useSelectedItems() const { effect, resetEffect } = useSidebar() - const { data: balance, mutate: revalidate } = useListBalance({ listId: list.id }) + const { data: balanceData, mutate: revalidate } = useListBalance({ listId: list.id }) + const balance = balanceData?.data const selectedMarket = list.markets.find((m) => m.market.id === selected[0]) const isTradable = selectedMarket ? isMarketTradable(selectedMarket) : false diff --git a/packages/lists/lib/getLists.ts b/packages/lists/lib/getLists.ts index 250d2d9b..1ee770ae 100644 --- a/packages/lists/lib/getLists.ts +++ b/packages/lists/lib/getLists.ts @@ -1,57 +1,34 @@ +import { getPaginatedItems, PaginationRequest } from '@play-money/api-helpers' import db, { List } from '@play-money/database' -import { ExtendedList } from '../types' interface ListFilterOptions { ownerId?: string } -interface SortOptions { - field: string - direction: 'asc' | 'desc' -} - -interface PaginationOptions { - skip: number - take: number -} - -export async function getLists( - filters: ListFilterOptions = {}, - sort: SortOptions = { field: 'createdAt', direction: 'desc' }, - pagination: PaginationOptions = { skip: 0, take: 10 } -): Promise<{ lists: Array; total: number }> { - const [lists, total] = await Promise.all([ - db.list.findMany({ - where: { - ownerId: filters.ownerId, - }, - include: { - owner: true, - markets: { - include: { - market: { - include: { - user: true, - options: true, - marketResolution: { - include: { - resolution: true, - resolvedBy: true, - }, +export async function getLists(filters: ListFilterOptions = {}, pagination?: PaginationRequest) { + return getPaginatedItems({ + model: db.list, + pagination: pagination ?? {}, + where: { + ownerId: filters.ownerId, + }, + include: { + owner: true, + markets: { + include: { + market: { + include: { + options: true, + marketResolution: { + include: { + resolution: true, + resolvedBy: true, }, }, }, }, }, }, - orderBy: { - [sort.field]: sort.direction, - }, - skip: pagination.skip, - take: pagination.take, - }), - db.list.count(), - ]) - - return { lists, total } + }, + }) } diff --git a/packages/markets/components/CreateMarketForm.tsx b/packages/markets/components/CreateMarketForm.tsx index 898391f3..29b1e120 100644 --- a/packages/markets/components/CreateMarketForm.tsx +++ b/packages/markets/components/CreateMarketForm.tsx @@ -102,7 +102,7 @@ export function CreateMarketForm({ async function onSubmit(market: MarketCreateFormValues) { try { - const created = await createMarket(market) + const { data: created } = await createMarket(market) clearPresistedData({ localStorageKey: CREATE_MARKET_FORM_KEY }) form.reset({}) @@ -198,7 +198,7 @@ export function CreateMarketForm({ async function handleQuestionBlur() { const question = form.getValues('question') if (!form.getValues('tags')?.length) { - const { tags } = await createMarketGenerateTags({ question }) + const { data: tags } = await createMarketGenerateTags({ question }) form.setValue('tags', tags) } diff --git a/packages/markets/components/MarketActivity.tsx b/packages/markets/components/MarketActivity.tsx index b52181cb..a234411f 100644 --- a/packages/markets/components/MarketActivity.tsx +++ b/packages/markets/components/MarketActivity.tsx @@ -26,7 +26,7 @@ function summarizeTransactions(transactions: Array) { } export async function MarketActivity({ marketId }: { marketId: string }) { - const { activities } = await getMarketActivity({ marketId }) + const { data: activities = [] } = await getMarketActivity({ marketId }) const handleRevalidate = async () => { 'use server' diff --git a/packages/markets/components/MarketBuyForm.tsx b/packages/markets/components/MarketBuyForm.tsx index efffbac2..68281c95 100644 --- a/packages/markets/components/MarketBuyForm.tsx +++ b/packages/markets/components/MarketBuyForm.tsx @@ -61,7 +61,7 @@ export function MarketBuyForm({ const fetchQuote = async (amount: number, optionId: string) => { try { - const data = await getMarketQuote({ marketId, optionId, amount }) + const { data } = await getMarketQuote({ marketId, optionId, amount }) setQuote(data) } catch (error) { console.error('Failed to fetch quote:', error) diff --git a/packages/markets/components/MarketComments.tsx b/packages/markets/components/MarketComments.tsx index e208f58b..efa39bb6 100644 --- a/packages/markets/components/MarketComments.tsx +++ b/packages/markets/components/MarketComments.tsx @@ -4,7 +4,7 @@ import { getMarketComments } from '@play-money/api-helpers/client' import { CommentsList } from '@play-money/comments/components/CommentsList' export async function MarketComments({ marketId }: { marketId: string }) { - const { comments } = await getMarketComments({ marketId }) + const { data: comments } = await getMarketComments({ marketId }) const handleRevalidate = async () => { 'use server' diff --git a/packages/markets/components/MarketLeaderboardPanel.tsx b/packages/markets/components/MarketLeaderboardPanel.tsx index f213e22e..04f9c937 100644 --- a/packages/markets/components/MarketLeaderboardPanel.tsx +++ b/packages/markets/components/MarketLeaderboardPanel.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { useMarketPositions } from '@play-money/api-helpers/client/hooks' +import { useMarketBalances } from '@play-money/api-helpers/client/hooks' import { CurrencyDisplay } from '@play-money/finance/components/CurrencyDisplay' import { Badge } from '@play-money/ui/badge' import { Card, CardContent } from '@play-money/ui/card' @@ -8,7 +8,8 @@ import { UserLink } from '@play-money/users/components/UserLink' import { ExtendedMarket } from '../types' export function MarketLeaderboardPanel({ market }: { market: ExtendedMarket }) { - const { data: positions } = useMarketPositions({ marketId: market.id }) + const { data: positionsData } = useMarketBalances({ marketId: market.id }) + const positions = positionsData?.data const userInLeaderboard = positions?.user && positions?.balances.find((b) => b.accountId === positions.user.accountId) return positions?.balances.length || positions?.user ? ( diff --git a/packages/markets/components/MarketLiquidityPage.tsx b/packages/markets/components/MarketLiquidityPage.tsx index 3d4a8f28..365962fb 100644 --- a/packages/markets/components/MarketLiquidityPage.tsx +++ b/packages/markets/components/MarketLiquidityPage.tsx @@ -1,6 +1,7 @@ import { format, isPast } from 'date-fns' import _ from 'lodash' import React from 'react' +import { PageInfo } from '@play-money/api-helpers' import { CurrencyDisplay } from '@play-money/finance/components/CurrencyDisplay' import { LiquidityTable } from '@play-money/finance/components/LiquidityTable' import { TransactionWithEntries } from '@play-money/finance/types' @@ -13,9 +14,11 @@ import { MarketToolbar } from './MarketToolbar' export function MarketLiquidityPage({ market, liquidityTransactions, + pageInfo, }: { market: ExtendedMarket liquidityTransactions: Array + pageInfo: PageInfo }) { const simplyIfTwoOptions = market.options.length === 2 @@ -55,7 +58,7 @@ export function MarketLiquidityPage({ {liquidityTransactions.length ? ( - + ) : (
    No liquidity has been added yet.
    )} diff --git a/packages/markets/components/MarketOverviewPage.tsx b/packages/markets/components/MarketOverviewPage.tsx index 4e8d6d8e..a7caf0c0 100644 --- a/packages/markets/components/MarketOverviewPage.tsx +++ b/packages/markets/components/MarketOverviewPage.tsx @@ -60,7 +60,8 @@ export function MarketOverviewPage({ const { user } = useUser() const { selected, setSelected } = useSelectedItems() const { triggerEffect } = useSidebar() - const { data: balance } = useMarketBalance({ marketId: market.id }) + const { data: balanceData } = useMarketBalance({ marketId: market.id }) + const balance = balanceData?.data const [isEditing, setIsEditing] = useSearchParam('edit') const [isEditOption, setIsEditOption] = useSearchParam('editOption') const [isBoosting, setIsBoosting] = useSearchParam('boost') diff --git a/packages/markets/components/MarketSellForm.tsx b/packages/markets/components/MarketSellForm.tsx index da0bb889..4756ccf2 100644 --- a/packages/markets/components/MarketSellForm.tsx +++ b/packages/markets/components/MarketSellForm.tsx @@ -67,7 +67,7 @@ export function MarketSellForm({ const fetchQuote = async (amount: number, optionId: string) => { try { - const data = await getMarketQuote({ marketId, optionId, amount, isBuy: false }) + const { data } = await getMarketQuote({ marketId, optionId, amount, isBuy: false }) setQuote(data) } catch (error) { console.error('Failed to fetch quote:', error) diff --git a/packages/markets/components/MarketTradePanel.tsx b/packages/markets/components/MarketTradePanel.tsx index df665e02..8e9d2f1d 100644 --- a/packages/markets/components/MarketTradePanel.tsx +++ b/packages/markets/components/MarketTradePanel.tsx @@ -36,8 +36,9 @@ export function MarketTradePanel({ }) { const { selected, setSelected } = useSelectedItems() // We can SSR this now, since the P&L will be the one thats updated externally and this one will only ever be updated by a user! - const { data: balance, mutate: revalidate } = useMarketBalance({ marketId: market.id }) + const { data: balanceData, mutate: revalidate } = useMarketBalance({ marketId: market.id }) const { effect, resetEffect } = useSidebar() + const balance = balanceData?.data const activeOption = market.options.find((o) => o.id === selected[0]) const activePosition = balance?.userPositions.find((p) => p.optionId === activeOption?.id) diff --git a/packages/markets/components/MarketTradesPage.stories.tsx b/packages/markets/components/MarketTradesPage.stories.tsx index e7ed941b..36b1909b 100644 --- a/packages/markets/components/MarketTradesPage.stories.tsx +++ b/packages/markets/components/MarketTradesPage.stories.tsx @@ -14,7 +14,10 @@ export const Default: Story = { args: { market: mockExtendedMarket(), transactions: [mockTransactionWithEntries(), mockTransactionWithEntries(), mockTransactionWithEntries()], - totalPages: 1, + pageInfo: { + hasNextPage: true, + total: 100, + }, }, } @@ -22,6 +25,9 @@ export const Empty: Story = { args: { market: mockExtendedMarket(), transactions: [], - totalPages: 1, + pageInfo: { + hasNextPage: false, + total: 0, + }, }, } diff --git a/packages/markets/components/MarketTradesPage.tsx b/packages/markets/components/MarketTradesPage.tsx index 410aed4f..693dc3e2 100644 --- a/packages/markets/components/MarketTradesPage.tsx +++ b/packages/markets/components/MarketTradesPage.tsx @@ -1,6 +1,7 @@ import { format, isPast } from 'date-fns' import _ from 'lodash' import React from 'react' +import { PageInfo } from '@play-money/api-helpers/types' import { CurrencyDisplay } from '@play-money/finance/components/CurrencyDisplay' import { TradesTable } from '@play-money/finance/components/TradesTable' import { TransactionWithEntries } from '@play-money/finance/types' @@ -13,11 +14,11 @@ import { MarketToolbar } from './MarketToolbar' export function MarketTradesPage({ market, transactions, - totalPages, + pageInfo, }: { market: ExtendedMarket transactions: Array - totalPages: number + pageInfo: PageInfo }) { const simplyIfTwoOptions = market.options.length === 2 @@ -57,7 +58,7 @@ export function MarketTradesPage({ {transactions.length ? ( - + ) : (
    No trades have been made yet.
    )} diff --git a/packages/markets/components/MarketsTable.tsx b/packages/markets/components/MarketsTable.tsx index 6d72c92e..987f48d3 100644 --- a/packages/markets/components/MarketsTable.tsx +++ b/packages/markets/components/MarketsTable.tsx @@ -4,6 +4,7 @@ import { ColumnDef, RowData } from '@tanstack/react-table' import { MinusIcon } from 'lucide-react' import Link from 'next/link' import React from 'react' +import { PageInfo } from '@play-money/api-helpers' import { User } from '@play-money/database' import { CurrencyDisplay } from '@play-money/finance/components/CurrencyDisplay' import { formatDistanceToNowShort } from '@play-money/ui' @@ -158,12 +159,12 @@ function MarketTableStatusSelect({ defaultValue = 'active' }: { defaultValue?: s ) } -export function MarketsTable({ data, totalPages }: { data: Array; totalPages: number }) { +export function MarketsTable({ data, pageInfo }: { data: Array; pageInfo: PageInfo }) { return ( diff --git a/packages/markets/components/RelatedMarkets.tsx b/packages/markets/components/RelatedMarkets.tsx index ac94ccfc..94fed8c1 100644 --- a/packages/markets/components/RelatedMarkets.tsx +++ b/packages/markets/components/RelatedMarkets.tsx @@ -6,13 +6,14 @@ import { useMarketRelated } from '@play-money/api-helpers/client/hooks' import { MarketProbabilityDetail } from './MarketProbabilityDetail' export function RelatedMarkets({ marketId, listId }: { marketId: string; listId?: string }) { - const { data } = useMarketRelated({ marketId }) + const { data: relatedData } = useMarketRelated({ marketId }) + const markets = relatedData?.data ?? [] - return data?.markets.length ? ( + return markets.length ? (
    Related Markets
      - {data.markets.map((market) => { + {markets.map((market) => { return (
    • diff --git a/packages/markets/lib/getMarketPositions.ts b/packages/markets/lib/getMarketPositions.ts index dd1fd357..a50f2e1e 100644 --- a/packages/markets/lib/getMarketPositions.ts +++ b/packages/markets/lib/getMarketPositions.ts @@ -1,4 +1,5 @@ import Decimal from 'decimal.js' +import { getPaginatedItems, PaginationRequest } from '@play-money/api-helpers' import db, { MarketOptionPosition } from '@play-money/database' interface MarketPositionFilterOptions { @@ -7,21 +8,7 @@ interface MarketPositionFilterOptions { marketId?: string } -interface SortOptions { - field: string - direction: 'asc' | 'desc' -} - -interface PaginationOptions { - skip: number - take: number -} - -export async function getMarketPositions( - filters: MarketPositionFilterOptions = {}, - sort: SortOptions = { field: 'createdAt', direction: 'desc' }, - pagination: PaginationOptions = { skip: 0, take: 10 } -): Promise<{ marketPositions: Array; total: number }> { +export async function getMarketPositions(filters: MarketPositionFilterOptions = {}, pagination?: PaginationRequest) { const statusFilters = filters.status === 'active' ? { @@ -39,44 +26,26 @@ export async function getMarketPositions( ? {} : {} - const [marketPositions, total] = await Promise.all([ - db.marketOptionPosition.findMany({ - where: { - ...statusFilters, - marketId: filters.marketId, - account: { - userPrimary: { - id: filters.ownerId, - }, + return getPaginatedItems({ + model: db.marketOptionPosition, + pagination: pagination ?? {}, + where: { + ...statusFilters, + marketId: filters.marketId, + account: { + userPrimary: { + id: filters.ownerId, }, }, - include: { - account: { - include: { - user: true, - }, + }, + include: { + account: { + include: { + user: true, }, - market: true, - option: true, }, - orderBy: { - [sort.field]: sort.direction, - }, - skip: pagination.skip, - take: pagination.take, - }), - db.marketOptionPosition.count({ - where: { - ...statusFilters, - marketId: filters.marketId, - account: { - userPrimary: { - id: filters.ownerId, - }, - }, - }, - }), - ]) - - return { marketPositions, total } + market: true, + option: true, + }, + }) } diff --git a/packages/markets/lib/getMarkets.ts b/packages/markets/lib/getMarkets.ts index 5488fe27..3bb40742 100644 --- a/packages/markets/lib/getMarkets.ts +++ b/packages/markets/lib/getMarkets.ts @@ -1,95 +1,60 @@ +import { getPaginatedItems, PaginationRequest } from '@play-money/api-helpers' import db, { Market } from '@play-money/database' import { ExtendedMarket } from '../types' interface MarketFilterOptions { status?: 'active' | 'halted' | 'closed' | 'resolved' | 'canceled' | 'all' createdBy?: string - tag?: string tags?: string[] } -interface SortOptions { - field: string - direction: 'asc' | 'desc' +function getStatusFilters(status: MarketFilterOptions['status']) { + switch (status) { + case 'active': + return { + closeDate: { gt: new Date() }, + resolvedAt: null, + canceledAt: null, + } + case 'closed': + return { + closeDate: { lt: new Date() }, + resolvedAt: null, + canceledAt: null, + } + case 'resolved': + return { + resolvedAt: { not: null }, + } + case 'canceled': + return { + canceledAt: { not: null }, + } + default: + return {} + } } -interface PaginationOptions { - skip: number - take: number -} - -export async function getMarkets( - filters: MarketFilterOptions = {}, - sort: SortOptions = { field: 'createdAt', direction: 'desc' }, - pagination: PaginationOptions = { skip: 0, take: 10 } -): Promise<{ markets: Array; total: number }> { - const statusFilters = - filters.status === 'active' - ? { - closeDate: { - gt: new Date(), - }, - resolvedAt: null, - canceledAt: null, - } - : filters.status === 'closed' - ? { - closeDate: { - lt: new Date(), - }, - resolvedAt: null, - canceledAt: null, - } - : filters.status === 'resolved' - ? { - resolvedAt: { - not: null, - }, - } - : filters.status === 'canceled' - ? { - canceledAt: { - not: null, - }, - } - : filters.status === 'all' - ? {} - : {} - - const [markets, total] = await Promise.all([ - db.market.findMany({ - where: { - ...statusFilters, - createdBy: filters.createdBy, - tags: filters.tag ? { has: filters.tag } : filters.tags ? { hasSome: filters.tags } : undefined, - parentListId: null, - }, - include: { - user: true, - options: true, - marketResolution: { - include: { - resolution: true, - resolvedBy: true, - }, +export async function getMarkets(filters: MarketFilterOptions = {}, pagination?: PaginationRequest) { + return getPaginatedItems({ + model: db.market, + pagination: pagination ?? {}, + where: { + ...getStatusFilters(filters.status), + createdBy: filters.createdBy, + tags: filters.tags ? { hasSome: filters.tags } : undefined, + parentListId: null, + }, + include: { + user: true, + options: true, + marketResolution: { + include: { + resolution: true, + resolvedBy: true, }, - parentList: true, }, - orderBy: { - [sort.field]: sort.direction, - }, - skip: pagination.skip, - take: pagination.take, - }), - db.market.count({ - where: { - ...statusFilters, - createdBy: filters.createdBy, - tags: filters.tag ? { has: filters.tag } : undefined, - parentListId: null, - }, - }), - ]) - - return { markets, total } + parentList: true, + }, + }) } diff --git a/packages/markets/lib/getNewLiquidityTransactions.ts b/packages/markets/lib/getNewLiquidityTransactions.ts deleted file mode 100644 index a15b9328..00000000 --- a/packages/markets/lib/getNewLiquidityTransactions.ts +++ /dev/null @@ -1,29 +0,0 @@ -import db from '@play-money/database' -import { getHouseAccount } from '@play-money/finance/lib/getHouseAccount' -import { TransactionWithEntries } from '@play-money/finance/types' - -export async function getNewLiquidityTransactions(): Promise> { - const houseAccount = await getHouseAccount() - const transactions = await db.transaction.findMany({ - where: { - type: 'LIQUIDITY_DEPOSIT', - entries: { - none: { - fromAccountId: houseAccount.id, - }, - }, - isReverse: null, - }, - orderBy: { - createdAt: 'desc', - }, - include: { - entries: true, - market: true, - initiator: true, - options: true, - }, - }) - - return transactions -} diff --git a/packages/markets/lib/getRelatedMarkets.ts b/packages/markets/lib/getRelatedMarkets.ts index 31e8905e..13a82f13 100644 --- a/packages/markets/lib/getRelatedMarkets.ts +++ b/packages/markets/lib/getRelatedMarkets.ts @@ -9,7 +9,7 @@ export async function getRelatedMarkets({ marketId }: { marketId: string }): Pro status: 'active', }) - const rankedMarkets = relatedMarkets.markets + const rankedMarkets = relatedMarkets.data .filter((relatedMarket) => relatedMarket.id !== marketId) .map((relatedMarket) => { const sharedTagsCount = relatedMarket.tags.filter((tag) => market.tags.includes(tag)).length diff --git a/packages/markets/lib/updateMarket.ts b/packages/markets/lib/updateMarket.ts index bed03728..1b6fb26b 100644 --- a/packages/markets/lib/updateMarket.ts +++ b/packages/markets/lib/updateMarket.ts @@ -7,12 +7,14 @@ export async function updateMarket({ description, closeDate, tags, + createdBy, }: { id: string question?: string description?: string closeDate?: Date tags?: Array + createdBy?: string }) { const updatedData: Partial = {} @@ -33,6 +35,10 @@ export async function updateMarket({ updatedData.tags = tags.map((tag) => slugifyTitle(tag)) } + if (createdBy) { + updatedData.createdBy = createdBy + } + const updatedMarket = await db.market.update({ where: { id }, data: { ...updatedData, updatedAt: new Date() }, diff --git a/packages/notifications/components/NotificationDropdown.tsx b/packages/notifications/components/NotificationDropdown.tsx index 55a17458..64860a35 100644 --- a/packages/notifications/components/NotificationDropdown.tsx +++ b/packages/notifications/components/NotificationDropdown.tsx @@ -15,7 +15,8 @@ import { NotificationItem } from './NotificationItem' export function NotificationDropdown() { const [isOpen, setIsOpen] = useState(false) const { user } = useUser() - const { data, mutate } = useNotifications({ skip: !user }) + const { data: notificationData, mutate } = useNotifications({ skip: !user }) + const data = notificationData?.data const handleMarkAllRead = async () => { try { diff --git a/packages/quests/components/UserQuestCard.tsx b/packages/quests/components/UserQuestCard.tsx index a03cd7f9..9cc9aebd 100644 --- a/packages/quests/components/UserQuestCard.tsx +++ b/packages/quests/components/UserQuestCard.tsx @@ -6,7 +6,8 @@ import { QuestCard } from './QuestCard' export function UserQuestCard() { const { user } = useUser() - const { data } = useUserStats({ userId: user?.id ?? '', skip: !user }) + const { data: statsData } = useUserStats({ userId: user?.id ?? '', skip: !user }) + const data = statsData?.data return user && data?.quests.length ? : null } diff --git a/packages/referrals/components/ReferralContext.tsx b/packages/referrals/components/ReferralContext.tsx index d52e45d2..1730640b 100644 --- a/packages/referrals/components/ReferralContext.tsx +++ b/packages/referrals/components/ReferralContext.tsx @@ -30,7 +30,7 @@ export const ReferralProvider = ({ children }: { children: ReactNode }) => { if (!user && code && Date.now() - timestamp < THIRTY_DAYS) { setIsLoading(true) try { - const user = await getUserReferral({ code }) + const { data: user } = await getUserReferral({ code }) setReferringUser(user) } catch (error) { console.error('Error fetching referral info:', error) diff --git a/packages/search/components/GlobalSearchMenu.tsx b/packages/search/components/GlobalSearchMenu.tsx index 5c9dd972..ce5cdc35 100644 --- a/packages/search/components/GlobalSearchMenu.tsx +++ b/packages/search/components/GlobalSearchMenu.tsx @@ -25,7 +25,7 @@ export function GlobalSearchMenu({ open, onOpenChange }: { open: boolean; onOpen useEffect(() => { async function search() { if (open) { - const data = await getSearch({ query }) + const { data } = await getSearch({ query }) setResults(data) } } diff --git a/packages/ui/src/components/ui/data-table-pagination.tsx b/packages/ui/src/components/ui/data-table-pagination.tsx index 8ca64153..08df9344 100644 --- a/packages/ui/src/components/ui/data-table-pagination.tsx +++ b/packages/ui/src/components/ui/data-table-pagination.tsx @@ -1,18 +1,22 @@ 'use client' import type { Table } from '@tanstack/react-table' -import { ChevronLeft, ChevronRight } from 'lucide-react' +import { ChevronRight } from 'lucide-react' import { useRouter } from 'next/navigation' import React from 'react' import useUpdateSearchParams from '../../hooks/useUpdateSearchParams' import { Button } from './button' +import type { PageInfo } from './data-table' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './select' interface DataTablePaginationProps { table: Table } -export function DataTablePagination({ table }: DataTablePaginationProps) { +export function DataTablePagination({ + table, + pageInfo, +}: DataTablePaginationProps & { pageInfo: PageInfo }) { const updateSearchParams = useUpdateSearchParams() const router = useRouter() @@ -28,7 +32,7 @@ export function DataTablePagination({ table }: DataTablePaginationProps { table.setPageSize(Number(value)) - updatePageSearchParams({ pageSize: value }) + updatePageSearchParams({ limit: value, cursor: '' }) }} value={`${table.getState().pagination.pageSize}`} > @@ -44,22 +48,11 @@ export function DataTablePagination({ table }: DataTablePaginationProps
    -
    + {/*
    Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()} -
    +
    */}
    {/* */} - + */} - {/* */}
    ) diff --git a/packages/ui/src/components/ui/data-table.tsx b/packages/ui/src/components/ui/data-table.tsx index 6ebd70a5..280a6064 100644 --- a/packages/ui/src/components/ui/data-table.tsx +++ b/packages/ui/src/components/ui/data-table.tsx @@ -26,10 +26,16 @@ declare module '@tanstack/react-table' { } } +export type PageInfo = { + hasNextPage: boolean + endCursor?: string + total: number +} + interface DataTableProps { columns: Array> data: Array - totalPages: number + pageInfo: PageInfo controls?: React.ReactNode showViewOptions?: boolean } @@ -58,15 +64,14 @@ function useURLSorting(): SortingOptions & { sorting: SortingState } { } } -function useURLPagination({ pageCount }: { pageCount: number }): PaginationOptions & { pagination: PaginationState } { - const [pageSize] = useSearchParam('pageSize') - const [page] = useSearchParam('page') +function useURLPagination({ total }: { total: number }): PaginationOptions & { pagination: PaginationState } { + const [pageSize] = useSearchParam('limit') const [pagination, setPagination] = useState({ - pageIndex: page ? parseInt(page) - 1 : 0, + pageIndex: -1, pageSize: pageSize ? parseInt(pageSize) : 50, }) - return { pagination, onPaginationChange: setPagination, manualPagination: true, pageCount } + return { pagination, onPaginationChange: setPagination, manualPagination: true, rowCount: total } } function useLocalStorageColumnVisibility(): VisibilityOptions & { columnVisibility: VisibilityState } { @@ -85,12 +90,13 @@ function useLocalStorageColumnVisibility(): VisibilityOptions & { columnVisibili export function DataTable({ data, columns, - totalPages, + pageInfo, + // eslint-disable-next-line react/jsx-no-useless-fragment -- empty controls are fine controls = <>, showViewOptions = true, }: DataTableProps) { const { sorting, ...sortingOptions } = useURLSorting() - const { pagination, ...paginationOptions } = useURLPagination({ pageCount: totalPages }) + const { pagination, ...paginationOptions } = useURLPagination({ total: pageInfo.total }) const { columnVisibility, ...columnVisibilityOptions } = useLocalStorageColumnVisibility() const table = useReactTable({ @@ -146,7 +152,7 @@ export function DataTable({
- +
) } diff --git a/packages/users/components/ActiveUserBalance.tsx b/packages/users/components/ActiveUserBalance.tsx index 279a09c9..61896044 100644 --- a/packages/users/components/ActiveUserBalance.tsx +++ b/packages/users/components/ActiveUserBalance.tsx @@ -6,7 +6,8 @@ import { useUser } from '@play-money/users/context/UserContext' export function ActiveUserBalance({ initialBalance }: { initialBalance?: number }) { const { user } = useUser() - const { data } = useMyBalance({ skip: !user }) + const { data: balanceData } = useMyBalance({ skip: !user }) + const data = balanceData?.data return user ? : null } diff --git a/packages/users/components/SettingsProfileForm.tsx b/packages/users/components/SettingsProfileForm.tsx index 063a295d..349e73fa 100644 --- a/packages/users/components/SettingsProfileForm.tsx +++ b/packages/users/components/SettingsProfileForm.tsx @@ -56,7 +56,7 @@ export function SettingsProfileForm({ async function onSubmit(data: ProfileFormValues) { try { - const user = await updateMe(data) + const { data: user } = await updateMe(data) setUser(user) toast({ @@ -142,7 +142,9 @@ export function SettingsProfileForm({ if (user?.username === value) { return true } - const { available, message } = await getUserCheckUsername({ username: value }) + const { + data: { available, message }, + } = await getUserCheckUsername({ username: value }) return available || message || 'There is an error with that username' }, 500, diff --git a/packages/users/components/UserPositionsTable.tsx b/packages/users/components/UserPositionsTable.tsx index 3c77dcd4..8f2a39ec 100644 --- a/packages/users/components/UserPositionsTable.tsx +++ b/packages/users/components/UserPositionsTable.tsx @@ -5,6 +5,7 @@ import Decimal from 'decimal.js' import _ from 'lodash' import Link from 'next/link' import React from 'react' +import { PageInfo } from '@play-money/api-helpers/types' import { Market, MarketOption, MarketOptionPosition } from '@play-money/database' import { CurrencyDisplay } from '@play-money/finance/components/CurrencyDisplay' import { ExtendedMarketPosition } from '@play-money/markets/types' @@ -107,12 +108,12 @@ function UserPositionsStatusSelect({ defaultValue = 'active' }: { defaultValue?: ) } -export function UserPositionsTable({ data, totalPages }: { data: Array; totalPages: number }) { +export function UserPositionsTable({ data, pageInfo }: { data: Array; pageInfo: PageInfo }) { return ( diff --git a/packages/users/components/UserProfileLayout.tsx b/packages/users/components/UserProfileLayout.tsx index 79b414d3..87c30368 100644 --- a/packages/users/components/UserProfileLayout.tsx +++ b/packages/users/components/UserProfileLayout.tsx @@ -49,9 +49,11 @@ export async function UserProfileLayout({ params: { username: string } children: React.ReactNode }) { - const profile = await getUserUsername({ username }) - const stats = await getUserStats({ userId: profile.id }) - const { balance } = await getUserBalance({ userId: profile.id }) + const { data: profile } = await getUserUsername({ username }) + const { data: stats } = await getUserStats({ userId: profile.id }) + const { + data: { balance }, + } = await getUserBalance({ userId: profile.id }) const quester = balance.subtotals['DAILY_TRADE_BONUS'] + diff --git a/packages/users/components/UserProfilePage.tsx b/packages/users/components/UserProfilePage.tsx index 4a518411..539525b0 100644 --- a/packages/users/components/UserProfilePage.tsx +++ b/packages/users/components/UserProfilePage.tsx @@ -5,7 +5,7 @@ import Link from 'next/link' import React from 'react' import { getMarketPositions, - getUserLists, + getLists, getUserMarkets, getUserPositions, getUserTransactions, @@ -24,7 +24,7 @@ import { UserPositionsTable } from './UserPositionsTable' import { UserProfileTabs } from './UserProfileTabs' export async function UserTradesTable({ userId }: { userId: string }) { - const { transactions } = await getUserTransactions({ userId }) + const { data: transactions } = await getUserTransactions({ userId }) return ( @@ -99,7 +99,7 @@ export async function UserTradesTable({ userId }: { userId: string }) { } export async function UserMarketsTable({ userId }: { userId: string }) { - const { markets } = await getUserMarkets({ userId }) + const { data: markets } = await getUserMarkets({ userId }) return (
@@ -136,7 +136,7 @@ export async function UserMarketsTable({ userId }: { userId: string }) { } export async function UserListsTable({ userId }: { userId: string }) { - const { lists } = await getUserLists({ userId }) + const { data: lists } = await getLists({ ownerId: userId }) return (
@@ -196,10 +196,10 @@ async function UserPositionsTab({ page?: string status?: 'active' | 'closed' | 'all' sortField?: string - sortDirection?: string + sortDirection?: 'asc' | 'desc' } }) { - const { marketPositions, totalPages } = await getMarketPositions({ + const { data: marketPositions, pageInfo } = await getMarketPositions({ ownerId: userId, ...filters, status: filters?.status ?? 'active', @@ -207,7 +207,7 @@ async function UserPositionsTab({ return (
- +
) } @@ -218,16 +218,18 @@ export async function UserProfilePage({ }: { username: string filters?: { - pageSize?: string - page?: string + limit?: string + cursor?: string status?: 'active' | 'closed' | 'all' sortField?: string - sortDirection?: string + sortDirection?: 'asc' | 'desc' } }) { - const user = await getUserUsername({ username }) - const { positions } = await getUserPositions({ userId: user.id, pageSize: 5 }) - const { markets } = await getUserMarkets({ userId: user.id }) + const { data: user } = await getUserUsername({ username }) + const { + data: { positions }, + } = await getUserPositions({ userId: user.id, pageSize: 5 }) + const { data: markets } = await getUserMarkets({ userId: user.id }) return (