mirror of
https://github.com/spliit-app/spliit.git
synced 2026-02-15 03:56:13 +01:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a11efc79c1 | ||
|
|
e63f3aa68f |
@@ -191,7 +191,7 @@ function ReceiptDialogContent() {
|
|||||||
<Unknown />
|
<Unknown />
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
'' || '…'
|
''
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import { calculateShare } from '@/lib/totals'
|
|||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { AppRouterOutput } from '@/trpc/routers/_app'
|
import { AppRouterOutput } from '@/trpc/routers/_app'
|
||||||
import { zodResolver } from '@hookform/resolvers/zod'
|
import { zodResolver } from '@hookform/resolvers/zod'
|
||||||
|
import { RecurrenceRule } from '@prisma/client'
|
||||||
import { Save } from 'lucide-react'
|
import { Save } from 'lucide-react'
|
||||||
import { useTranslations } from 'next-intl'
|
import { useTranslations } from 'next-intl'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
@@ -54,7 +55,6 @@ import { match } from 'ts-pattern'
|
|||||||
import { DeletePopup } from '../../../../components/delete-popup'
|
import { DeletePopup } from '../../../../components/delete-popup'
|
||||||
import { extractCategoryFromTitle } from '../../../../components/expense-form-actions'
|
import { extractCategoryFromTitle } from '../../../../components/expense-form-actions'
|
||||||
import { Textarea } from '../../../../components/ui/textarea'
|
import { Textarea } from '../../../../components/ui/textarea'
|
||||||
import { RecurrenceRule } from '@prisma/client'
|
|
||||||
|
|
||||||
const enforceCurrencyPattern = (value: string) =>
|
const enforceCurrencyPattern = (value: string) =>
|
||||||
value
|
value
|
||||||
@@ -190,7 +190,7 @@ export function ExpenseForm({
|
|||||||
isReimbursement: expense.isReimbursement,
|
isReimbursement: expense.isReimbursement,
|
||||||
documents: expense.documents,
|
documents: expense.documents,
|
||||||
notes: expense.notes ?? '',
|
notes: expense.notes ?? '',
|
||||||
recurrenceRule: expense.recurrenceRule,
|
recurrenceRule: expense.recurrenceRule ?? undefined,
|
||||||
}
|
}
|
||||||
: searchParams.get('reimbursement')
|
: searchParams.get('reimbursement')
|
||||||
? {
|
? {
|
||||||
@@ -516,7 +516,7 @@ export function ExpenseForm({
|
|||||||
defaultValue={getSelectedRecurrenceRule(field)}
|
defaultValue={getSelectedRecurrenceRule(field)}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="NONE"/>
|
<SelectValue placeholder="NONE" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="NONE">
|
<SelectItem value="NONE">
|
||||||
|
|||||||
241
src/lib/api.ts
241
src/lib/api.ts
@@ -1,6 +1,11 @@
|
|||||||
import { prisma } from '@/lib/prisma'
|
import { prisma } from '@/lib/prisma'
|
||||||
import { ExpenseFormValues, GroupFormValues } from '@/lib/schemas'
|
import { ExpenseFormValues, GroupFormValues } from '@/lib/schemas'
|
||||||
import { ActivityType, Expense, RecurrenceRule, RecurringExpenseLink } from '@prisma/client'
|
import {
|
||||||
|
ActivityType,
|
||||||
|
Expense,
|
||||||
|
RecurrenceRule,
|
||||||
|
RecurringExpenseLink,
|
||||||
|
} from '@prisma/client'
|
||||||
import { nanoid } from 'nanoid'
|
import { nanoid } from 'nanoid'
|
||||||
|
|
||||||
export function randomId() {
|
export function randomId() {
|
||||||
@@ -50,11 +55,12 @@ export async function createExpense(
|
|||||||
data: expenseFormValues.title,
|
data: expenseFormValues.title,
|
||||||
})
|
})
|
||||||
|
|
||||||
const isCreateRecurrence = expenseFormValues.recurrenceRule !== RecurrenceRule.NONE
|
const isCreateRecurrence =
|
||||||
|
expenseFormValues.recurrenceRule !== RecurrenceRule.NONE
|
||||||
const recurringExpenseLinkPayload = createPayloadForNewRecurringExpenseLink(
|
const recurringExpenseLinkPayload = createPayloadForNewRecurringExpenseLink(
|
||||||
expenseFormValues.recurrenceRule as RecurrenceRule,
|
expenseFormValues.recurrenceRule as RecurrenceRule,
|
||||||
expenseFormValues.expenseDate,
|
expenseFormValues.expenseDate,
|
||||||
groupId
|
groupId,
|
||||||
)
|
)
|
||||||
|
|
||||||
return prisma.expense.create({
|
return prisma.expense.create({
|
||||||
@@ -71,11 +77,9 @@ export async function createExpense(
|
|||||||
recurringExpenseLink: {
|
recurringExpenseLink: {
|
||||||
...(isCreateRecurrence
|
...(isCreateRecurrence
|
||||||
? {
|
? {
|
||||||
create: recurringExpenseLinkPayload
|
create: recurringExpenseLinkPayload,
|
||||||
}
|
}
|
||||||
: {}
|
: {}),
|
||||||
),
|
|
||||||
|
|
||||||
},
|
},
|
||||||
paidFor: {
|
paidFor: {
|
||||||
createMany: {
|
createMany: {
|
||||||
@@ -169,30 +173,31 @@ export async function updateExpense(
|
|||||||
data: expenseFormValues.title,
|
data: expenseFormValues.title,
|
||||||
})
|
})
|
||||||
|
|
||||||
const isDeleteRecurrenceExpenseLink =
|
const isDeleteRecurrenceExpenseLink =
|
||||||
existingExpense.recurrenceRule !== RecurrenceRule.NONE &&
|
existingExpense.recurrenceRule !== RecurrenceRule.NONE &&
|
||||||
expenseFormValues.recurrenceRule === RecurrenceRule.NONE &&
|
expenseFormValues.recurrenceRule === RecurrenceRule.NONE &&
|
||||||
// Delete the existing RecurrenceExpenseLink only if it has not been acted upon yet
|
// Delete the existing RecurrenceExpenseLink only if it has not been acted upon yet
|
||||||
existingExpense.recurringExpenseLink?.nextExpenseCreatedAt === null
|
existingExpense.recurringExpenseLink?.nextExpenseCreatedAt === null
|
||||||
|
|
||||||
const isUpdateRecurrenceExpenseLink = existingExpense.recurrenceRule !== expenseFormValues.recurrenceRule &&
|
const isUpdateRecurrenceExpenseLink =
|
||||||
|
existingExpense.recurrenceRule !== expenseFormValues.recurrenceRule &&
|
||||||
// Update the exisiting RecurrenceExpenseLink only if it has not been acted upon yet
|
// Update the exisiting RecurrenceExpenseLink only if it has not been acted upon yet
|
||||||
existingExpense.recurringExpenseLink?.nextExpenseCreatedAt === null
|
existingExpense.recurringExpenseLink?.nextExpenseCreatedAt === null
|
||||||
const isCreateRecurrenceExpenseLink =
|
const isCreateRecurrenceExpenseLink =
|
||||||
existingExpense.recurrenceRule === RecurrenceRule.NONE &&
|
existingExpense.recurrenceRule === RecurrenceRule.NONE &&
|
||||||
expenseFormValues.recurrenceRule !== RecurrenceRule.NONE &&
|
expenseFormValues.recurrenceRule !== RecurrenceRule.NONE &&
|
||||||
// Create a new RecurrenceExpenseLink only if one does not already exist for the expense
|
// Create a new RecurrenceExpenseLink only if one does not already exist for the expense
|
||||||
existingExpense.recurringExpenseLink === null
|
existingExpense.recurringExpenseLink === null
|
||||||
|
|
||||||
const newRecurringExpenseLink = createPayloadForNewRecurringExpenseLink(
|
const newRecurringExpenseLink = createPayloadForNewRecurringExpenseLink(
|
||||||
expenseFormValues.recurrenceRule as RecurrenceRule,
|
expenseFormValues.recurrenceRule as RecurrenceRule,
|
||||||
expenseFormValues.expenseDate,
|
expenseFormValues.expenseDate,
|
||||||
groupId
|
groupId,
|
||||||
)
|
)
|
||||||
|
|
||||||
const updatedRecurrenceExpenseLinkNextExpenseDate = calculateNextDate(
|
const updatedRecurrenceExpenseLinkNextExpenseDate = calculateNextDate(
|
||||||
expenseFormValues.recurrenceRule as RecurrenceRule,
|
expenseFormValues.recurrenceRule as RecurrenceRule,
|
||||||
existingExpense.expenseDate
|
existingExpense.expenseDate,
|
||||||
)
|
)
|
||||||
|
|
||||||
return prisma.expense.update({
|
return prisma.expense.update({
|
||||||
@@ -238,18 +243,16 @@ export async function updateExpense(
|
|||||||
recurringExpenseLink: {
|
recurringExpenseLink: {
|
||||||
...(isCreateRecurrenceExpenseLink
|
...(isCreateRecurrenceExpenseLink
|
||||||
? {
|
? {
|
||||||
create: newRecurringExpenseLink
|
create: newRecurringExpenseLink,
|
||||||
}
|
}
|
||||||
: {}
|
: {}),
|
||||||
),
|
|
||||||
...(isUpdateRecurrenceExpenseLink
|
...(isUpdateRecurrenceExpenseLink
|
||||||
? {
|
? {
|
||||||
update: {
|
update: {
|
||||||
nextExpenseDate: updatedRecurrenceExpenseLinkNextExpenseDate
|
nextExpenseDate: updatedRecurrenceExpenseLinkNextExpenseDate,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
: {}),
|
||||||
: {}
|
|
||||||
),
|
|
||||||
delete: isDeleteRecurrenceExpenseLink,
|
delete: isDeleteRecurrenceExpenseLink,
|
||||||
},
|
},
|
||||||
isReimbursement: expenseFormValues.isReimbursement,
|
isReimbursement: expenseFormValues.isReimbursement,
|
||||||
@@ -371,7 +374,13 @@ export async function getGroupExpenseCount(groupId: string) {
|
|||||||
export async function getExpense(groupId: string, expenseId: string) {
|
export async function getExpense(groupId: string, expenseId: string) {
|
||||||
return prisma.expense.findUnique({
|
return prisma.expense.findUnique({
|
||||||
where: { id: expenseId },
|
where: { id: expenseId },
|
||||||
include: { paidBy: true, paidFor: true, category: true, documents: true, recurringExpenseLink: true },
|
include: {
|
||||||
|
paidBy: true,
|
||||||
|
paidFor: true,
|
||||||
|
category: true,
|
||||||
|
documents: true,
|
||||||
|
recurringExpenseLink: true,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,35 +429,38 @@ export async function logActivity(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createRecurringExpenses(){
|
async function createRecurringExpenses() {
|
||||||
const localDate = new Date(); // Current local date
|
const localDate = new Date() // Current local date
|
||||||
const utcDateFromLocal = new Date(Date.UTC(
|
const utcDateFromLocal = new Date(
|
||||||
|
Date.UTC(
|
||||||
localDate.getUTCFullYear(),
|
localDate.getUTCFullYear(),
|
||||||
localDate.getUTCMonth(),
|
localDate.getUTCMonth(),
|
||||||
localDate.getUTCDate(),
|
localDate.getUTCDate(),
|
||||||
// More precision beyond date is required to ensure that recurring Expenses are created within <most precises unit> of when expected
|
// More precision beyond date is required to ensure that recurring Expenses are created within <most precises unit> of when expected
|
||||||
localDate.getUTCHours(),
|
localDate.getUTCHours(),
|
||||||
localDate.getUTCMinutes(),
|
localDate.getUTCMinutes(),
|
||||||
));
|
),
|
||||||
|
)
|
||||||
|
|
||||||
const recurringExpenseLinksWithExpensesToCreate = await prisma.recurringExpenseLink.findMany({
|
const recurringExpenseLinksWithExpensesToCreate =
|
||||||
where: {
|
await prisma.recurringExpenseLink.findMany({
|
||||||
nextExpenseCreatedAt: null,
|
where: {
|
||||||
nextExpenseDate: {
|
nextExpenseCreatedAt: null,
|
||||||
lte: utcDateFromLocal
|
nextExpenseDate: {
|
||||||
}
|
lte: utcDateFromLocal,
|
||||||
},
|
|
||||||
include: {
|
|
||||||
currentFrameExpense: {
|
|
||||||
include: {
|
|
||||||
paidBy: true,
|
|
||||||
paidFor: true,
|
|
||||||
category: true,
|
|
||||||
documents: true
|
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
include: {
|
||||||
})
|
currentFrameExpense: {
|
||||||
|
include: {
|
||||||
|
paidBy: true,
|
||||||
|
paidFor: true,
|
||||||
|
category: true,
|
||||||
|
documents: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
for (const recurringExpenseLink of recurringExpenseLinksWithExpensesToCreate) {
|
for (const recurringExpenseLink of recurringExpenseLinksWithExpensesToCreate) {
|
||||||
let newExpenseDate = recurringExpenseLink.nextExpenseDate
|
let newExpenseDate = recurringExpenseLink.nextExpenseDate
|
||||||
@@ -459,74 +471,84 @@ async function createRecurringExpenses(){
|
|||||||
while (newExpenseDate < utcDateFromLocal) {
|
while (newExpenseDate < utcDateFromLocal) {
|
||||||
const newExpenseId = randomId()
|
const newExpenseId = randomId()
|
||||||
const newRecurringExpenseLinkId = randomId()
|
const newRecurringExpenseLinkId = randomId()
|
||||||
|
|
||||||
const newRecurringExpenseNextExpenseDate = calculateNextDate(
|
const newRecurringExpenseNextExpenseDate = calculateNextDate(
|
||||||
currentExpenseRecord.recurrenceRule as RecurrenceRule,
|
currentExpenseRecord.recurrenceRule as RecurrenceRule,
|
||||||
newExpenseDate
|
newExpenseDate,
|
||||||
)
|
)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
category, paidBy, paidFor, documents,
|
category,
|
||||||
|
paidBy,
|
||||||
|
paidFor,
|
||||||
|
documents,
|
||||||
...destructeredCurrentExpenseRecord
|
...destructeredCurrentExpenseRecord
|
||||||
} = currentExpenseRecord
|
} = currentExpenseRecord
|
||||||
|
|
||||||
// Use a transacton to ensure that the only one expense is created for the RecurringExpenseLink
|
// Use a transacton to ensure that the only one expense is created for the RecurringExpenseLink
|
||||||
// just in case two clients are processing the same RecurringExpenseLink at the same time
|
// just in case two clients are processing the same RecurringExpenseLink at the same time
|
||||||
const newExpense = await prisma.$transaction(async (transaction) => {
|
const newExpense = await prisma
|
||||||
const newExpense = await transaction.expense.create({
|
.$transaction(async (transaction) => {
|
||||||
data: {
|
const newExpense = await transaction.expense.create({
|
||||||
...destructeredCurrentExpenseRecord,
|
data: {
|
||||||
categoryId: currentExpenseRecord.categoryId,
|
...destructeredCurrentExpenseRecord,
|
||||||
paidById: currentExpenseRecord.paidById,
|
categoryId: currentExpenseRecord.categoryId,
|
||||||
paidFor: {
|
paidById: currentExpenseRecord.paidById,
|
||||||
createMany: {
|
paidFor: {
|
||||||
data: currentExpenseRecord.paidFor.map((paidFor) => ({
|
createMany: {
|
||||||
participantId: paidFor.participantId,
|
data: currentExpenseRecord.paidFor.map((paidFor) => ({
|
||||||
shares: paidFor.shares,
|
participantId: paidFor.participantId,
|
||||||
})),
|
shares: paidFor.shares,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
documents: {
|
||||||
|
connect: currentExpenseRecord.documents.map(
|
||||||
|
(documentRecord) => ({
|
||||||
|
id: documentRecord.id,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
id: newExpenseId,
|
||||||
|
expenseDate: newExpenseDate,
|
||||||
|
recurringExpenseLink: {
|
||||||
|
create: {
|
||||||
|
groupId: currentExpenseRecord.groupId,
|
||||||
|
id: newRecurringExpenseLinkId,
|
||||||
|
nextExpenseDate: newRecurringExpenseNextExpenseDate,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
documents: {
|
// Ensure that the same information is available on the returned record that was created
|
||||||
connect: currentExpenseRecord.documents.map((documentRecord) => ({
|
include: {
|
||||||
id: documentRecord.id
|
paidFor: true,
|
||||||
})),
|
documents: true,
|
||||||
|
category: true,
|
||||||
|
paidBy: true,
|
||||||
},
|
},
|
||||||
id: newExpenseId,
|
})
|
||||||
expenseDate: newExpenseDate,
|
|
||||||
recurringExpenseLink: {
|
|
||||||
create: {
|
|
||||||
groupId: currentExpenseRecord.groupId,
|
|
||||||
id: newRecurringExpenseLinkId,
|
|
||||||
nextExpenseDate: newRecurringExpenseNextExpenseDate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Ensure that the same information is available on the returned record that was created
|
|
||||||
include: {
|
|
||||||
paidFor: true,
|
|
||||||
documents: true,
|
|
||||||
category: true,
|
|
||||||
paidBy: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Mark the RecurringExpenseLink as being "completed" since the new Expense was created
|
// Mark the RecurringExpenseLink as being "completed" since the new Expense was created
|
||||||
// if an expense hasn't been created for this RecurringExpenseLink yet
|
// if an expense hasn't been created for this RecurringExpenseLink yet
|
||||||
await transaction.recurringExpenseLink.update({
|
await transaction.recurringExpenseLink.update({
|
||||||
where: {
|
where: {
|
||||||
id: currentReccuringExpenseLinkId,
|
id: currentReccuringExpenseLinkId,
|
||||||
nextExpenseCreatedAt: null,
|
nextExpenseCreatedAt: null,
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
nextExpenseCreatedAt: newExpense.createdAt
|
nextExpenseCreatedAt: newExpense.createdAt,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return newExpense
|
return newExpense
|
||||||
}).catch(() => {
|
})
|
||||||
console.error("Failed to created recurringExpense for expenseId: %s", currentExpenseRecord.id)
|
.catch(() => {
|
||||||
return null
|
console.error(
|
||||||
})
|
'Failed to created recurringExpense for expenseId: %s',
|
||||||
|
currentExpenseRecord.id,
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
// If the new expense failed to be created, break out of the while-loop
|
// If the new expense failed to be created, break out of the while-loop
|
||||||
if (newExpense === null) break
|
if (newExpense === null) break
|
||||||
@@ -545,15 +567,15 @@ function createPayloadForNewRecurringExpenseLink(
|
|||||||
groupId: String,
|
groupId: String,
|
||||||
): RecurringExpenseLink {
|
): RecurringExpenseLink {
|
||||||
const nextExpenseDate = calculateNextDate(
|
const nextExpenseDate = calculateNextDate(
|
||||||
recurrenceRule,
|
recurrenceRule,
|
||||||
priorDateToNextRecurrence
|
priorDateToNextRecurrence,
|
||||||
)
|
)
|
||||||
|
|
||||||
const recurringExpenseLinkId = randomId()
|
const recurringExpenseLinkId = randomId()
|
||||||
const recurringExpenseLinkPayload = {
|
const recurringExpenseLinkPayload = {
|
||||||
id: recurringExpenseLinkId,
|
id: recurringExpenseLinkId,
|
||||||
groupId: groupId,
|
groupId: groupId,
|
||||||
nextExpenseDate: nextExpenseDate
|
nextExpenseDate: nextExpenseDate,
|
||||||
}
|
}
|
||||||
|
|
||||||
return recurringExpenseLinkPayload as RecurringExpenseLink
|
return recurringExpenseLinkPayload as RecurringExpenseLink
|
||||||
@@ -567,10 +589,10 @@ function createPayloadForNewRecurringExpenseLink(
|
|||||||
// will be created for Feb 28th, March 28, etc. until it is cancelled or fixed
|
// will be created for Feb 28th, March 28, etc. until it is cancelled or fixed
|
||||||
function calculateNextDate(
|
function calculateNextDate(
|
||||||
recurrenceRule: RecurrenceRule,
|
recurrenceRule: RecurrenceRule,
|
||||||
priorDateToNextRecurrence: Date
|
priorDateToNextRecurrence: Date,
|
||||||
): Date {
|
): Date {
|
||||||
const nextDate = new Date(priorDateToNextRecurrence)
|
const nextDate = new Date(priorDateToNextRecurrence)
|
||||||
switch(recurrenceRule) {
|
switch (recurrenceRule) {
|
||||||
case RecurrenceRule.DAILY:
|
case RecurrenceRule.DAILY:
|
||||||
nextDate.setUTCDate(nextDate.getUTCDate() + 1)
|
nextDate.setUTCDate(nextDate.getUTCDate() + 1)
|
||||||
break
|
break
|
||||||
@@ -578,7 +600,7 @@ function calculateNextDate(
|
|||||||
nextDate.setUTCDate(nextDate.getUTCDate() + 7)
|
nextDate.setUTCDate(nextDate.getUTCDate() + 7)
|
||||||
break
|
break
|
||||||
case RecurrenceRule.MONTHLY:
|
case RecurrenceRule.MONTHLY:
|
||||||
const nextYear = nextDate.getUTCFullYear()
|
const nextYear = nextDate.getUTCFullYear()
|
||||||
const nextMonth = nextDate.getUTCMonth() + 1
|
const nextMonth = nextDate.getUTCMonth() + 1
|
||||||
let nextDay = nextDate.getUTCDate()
|
let nextDay = nextDate.getUTCDate()
|
||||||
|
|
||||||
@@ -596,15 +618,12 @@ function calculateNextDate(
|
|||||||
function isDateInNextMonth(
|
function isDateInNextMonth(
|
||||||
utcYear: number,
|
utcYear: number,
|
||||||
utcMonth: number,
|
utcMonth: number,
|
||||||
utcDate: number
|
utcDate: number,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
const testDate = new Date(Date.UTC(
|
const testDate = new Date(Date.UTC(utcYear, utcMonth, utcDate))
|
||||||
utcYear, utcMonth, utcDate
|
|
||||||
))
|
|
||||||
|
|
||||||
// We're not concerned if the year or month changes. We only want to make sure that the date is our target date
|
// We're not concerned if the year or month changes. We only want to make sure that the date is our target date
|
||||||
if (testDate.getUTCDate() !== utcDate
|
if (testDate.getUTCDate() !== utcDate) {
|
||||||
) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { SplitMode, RecurrenceRule } from '@prisma/client'
|
import { RecurrenceRule, SplitMode } from '@prisma/client'
|
||||||
import * as z from 'zod'
|
import * as z from 'zod'
|
||||||
|
|
||||||
export const groupFormSchema = z
|
export const groupFormSchema = z
|
||||||
@@ -105,9 +105,9 @@ export const expenseFormSchema = z
|
|||||||
)
|
)
|
||||||
.default([]),
|
.default([]),
|
||||||
notes: z.string().optional(),
|
notes: z.string().optional(),
|
||||||
recurrenceRule:z
|
recurrenceRule: z
|
||||||
.enum<RecurrenceRule, [RecurrenceRule, ...RecurrenceRule[]]>(
|
.enum<RecurrenceRule, [RecurrenceRule, ...RecurrenceRule[]]>(
|
||||||
Object.values(RecurrenceRule) as any
|
Object.values(RecurrenceRule) as any,
|
||||||
)
|
)
|
||||||
.default('NONE'),
|
.default('NONE'),
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user