diff options
| author | Sebastien Castiel <sebastien@castiel.me> | 2024-01-28 18:51:29 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-28 18:51:29 -0500 |
| commit | d43e731fe191d7e35d96847fe095c94555dd8ca6 (patch) | |
| tree | b8bc3f99770a47ec0343f642ca04e727f7abd716 /src/lib | |
| parent | 11d2e298e8cc5cac07aa2c60e194bf4460cefb21 (diff) | |
Attach documents to expenses (#64)
* Upload documents to receipts
* Improve documents
* Make the feature opt-in
* Fix file name issue
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/api.ts | 28 | ||||
| -rw-r--r-- | src/lib/env.ts | 47 | ||||
| -rw-r--r-- | src/lib/schemas.ts | 10 |
3 files changed, 71 insertions, 14 deletions
diff --git a/src/lib/api.ts b/src/lib/api.ts index c27e584..dfa9651 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -62,6 +62,16 @@ export async function createExpense( }, }, isReimbursement: expenseFormValues.isReimbursement, + documents: { + createMany: { + data: expenseFormValues.documents.map((doc) => ({ + id: randomId(), + url: doc.url, + width: doc.width, + height: doc.height, + })), + }, + }, }, }) } @@ -159,6 +169,22 @@ export async function updateExpense( ), }, isReimbursement: expenseFormValues.isReimbursement, + documents: { + connectOrCreate: expenseFormValues.documents.map((doc) => ({ + create: doc, + where: { id: doc.id }, + })), + deleteMany: existingExpense.documents + .filter( + (existingDoc) => + !expenseFormValues.documents.some( + (doc) => doc.id === existingDoc.id, + ), + ) + .map((doc) => ({ + id: doc.id, + })), + }, }, }) } @@ -231,6 +257,6 @@ export async function getExpense(groupId: string, expenseId: string) { const prisma = await getPrisma() return prisma.expense.findUnique({ where: { id: expenseId }, - include: { paidBy: true, paidFor: true, category: true }, + include: { paidBy: true, paidFor: true, category: true, documents: true }, }) } diff --git a/src/lib/env.ts b/src/lib/env.ts index 3db102e..9912945 100644 --- a/src/lib/env.ts +++ b/src/lib/env.ts @@ -1,16 +1,37 @@ -import { z } from 'zod' +import { ZodIssueCode, z } from 'zod' -const envSchema = z.object({ - POSTGRES_URL_NON_POOLING: z.string().url(), - POSTGRES_PRISMA_URL: z.string().url(), - NEXT_PUBLIC_BASE_URL: z - .string() - .optional() - .default( - process.env.VERCEL_URL - ? `https://${process.env.VERCEL_URL}` - : 'http://localhost:3000', - ), -}) +const envSchema = z + .object({ + POSTGRES_URL_NON_POOLING: z.string().url(), + POSTGRES_PRISMA_URL: z.string().url(), + NEXT_PUBLIC_BASE_URL: z + .string() + .optional() + .default( + process.env.VERCEL_URL + ? `https://${process.env.VERCEL_URL}` + : 'http://localhost:3000', + ), + NEXT_PUBLIC_ENABLE_EXPENSE_DOCUMENTS: z.coerce.boolean().default(false), + S3_UPLOAD_KEY: z.string().optional(), + S3_UPLOAD_SECRET: z.string().optional(), + S3_UPLOAD_BUCKET: z.string().optional(), + S3_UPLOAD_REGION: z.string().optional(), + }) + .superRefine((env, ctx) => { + if ( + env.NEXT_PUBLIC_ENABLE_EXPENSE_DOCUMENTS && + (!env.S3_UPLOAD_BUCKET || + !env.S3_UPLOAD_KEY || + !env.S3_UPLOAD_REGION || + !env.S3_UPLOAD_SECRET) + ) { + ctx.addIssue({ + code: ZodIssueCode.custom, + message: + 'If NEXT_PUBLIC_ENABLE_EXPENSE_DOCUMENTS is specified, then S3_* must be specified too', + }) + } + }) export const env = envSchema.parse(process.env) diff --git a/src/lib/schemas.ts b/src/lib/schemas.ts index be90481..981cea3 100644 --- a/src/lib/schemas.ts +++ b/src/lib/schemas.ts @@ -105,6 +105,16 @@ export const expenseFormSchema = z ) .default('EVENLY'), isReimbursement: z.boolean(), + documents: z + .array( + z.object({ + id: z.string(), + url: z.string().url(), + width: z.number().int().min(1), + height: z.number().int().min(1), + }), + ) + .default([]), }) .superRefine((expense, ctx) => { let sum = 0 |
