aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorSebastien Castiel <sebastien@castiel.me>2024-01-28 18:51:29 -0500
committerGitHub <noreply@github.com>2024-01-28 18:51:29 -0500
commitd43e731fe191d7e35d96847fe095c94555dd8ca6 (patch)
treeb8bc3f99770a47ec0343f642ca04e727f7abd716 /src/lib
parent11d2e298e8cc5cac07aa2c60e194bf4460cefb21 (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.ts28
-rw-r--r--src/lib/env.ts47
-rw-r--r--src/lib/schemas.ts10
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