mirror of
https://github.com/spliit-app/spliit.git
synced 2026-03-01 02:46:12 +01:00
Add Expense Date (#26)
* add expense date * Improve date formatting * Prettier * Change field description --------- Co-authored-by: Sebastien Castiel <sebastien@castiel.me>
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Expense" ADD COLUMN "expenseDate" DATE NOT NULL DEFAULT CURRENT_DATE;
|
||||||
@@ -32,6 +32,7 @@ model Participant {
|
|||||||
model Expense {
|
model Expense {
|
||||||
id String @id
|
id String @id
|
||||||
group Group @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
group Group @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
||||||
|
expenseDate DateTime @db.Date @default(dbgenerated("CURRENT_DATE"))
|
||||||
title String
|
title String
|
||||||
amount Int
|
amount Int
|
||||||
paidBy Participant @relation(fields: [paidById], references: [id], onDelete: Cascade)
|
paidBy Participant @relation(fields: [paidById], references: [id], onDelete: Cascade)
|
||||||
|
|||||||
@@ -41,7 +41,10 @@ export function ExpenseList({
|
|||||||
{expense.title}
|
{expense.title}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-muted-foreground">
|
<div className="text-xs text-muted-foreground">
|
||||||
Paid by <strong>{getParticipant(expense.paidById)?.name}</strong>{' '}
|
Paid by <strong>{getParticipant(expense.paidById)?.name}</strong> on{' '}
|
||||||
|
{expense.expenseDate.toLocaleDateString('en-US', {
|
||||||
|
dateStyle: 'medium',
|
||||||
|
})}{' '}
|
||||||
for{' '}
|
for{' '}
|
||||||
{expense.paidFor.map((paidFor, index) => (
|
{expense.paidFor.map((paidFor, index) => (
|
||||||
<Fragment key={index}>
|
<Fragment key={index}>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
'use server'
|
'use server'
|
||||||
import { getGroups } from "@/lib/api"
|
import { getGroups } from '@/lib/api'
|
||||||
|
|
||||||
export async function getGroupsAction(groupIds: string[]) {
|
export async function getGroupsAction(groupIds: string[]) {
|
||||||
'use server'
|
'use server'
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ export function ExpenseForm({ group, expense, onSubmit, onDelete }: Props) {
|
|||||||
defaultValues: expense
|
defaultValues: expense
|
||||||
? {
|
? {
|
||||||
title: expense.title,
|
title: expense.title,
|
||||||
|
expenseDate: expense.expenseDate ?? new Date(),
|
||||||
amount: String(expense.amount / 100) as unknown as number, // hack
|
amount: String(expense.amount / 100) as unknown as number, // hack
|
||||||
paidBy: expense.paidById,
|
paidBy: expense.paidById,
|
||||||
paidFor: expense.paidFor.map(({ participantId, shares }) => ({
|
paidFor: expense.paidFor.map(({ participantId, shares }) => ({
|
||||||
@@ -68,6 +69,7 @@ export function ExpenseForm({ group, expense, onSubmit, onDelete }: Props) {
|
|||||||
: searchParams.get('reimbursement')
|
: searchParams.get('reimbursement')
|
||||||
? {
|
? {
|
||||||
title: 'Reimbursement',
|
title: 'Reimbursement',
|
||||||
|
expenseDate: new Date(),
|
||||||
amount: String(
|
amount: String(
|
||||||
(Number(searchParams.get('amount')) || 0) / 100,
|
(Number(searchParams.get('amount')) || 0) / 100,
|
||||||
) as unknown as number, // hack
|
) as unknown as number, // hack
|
||||||
@@ -81,6 +83,7 @@ export function ExpenseForm({ group, expense, onSubmit, onDelete }: Props) {
|
|||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
title: '',
|
title: '',
|
||||||
|
expenseDate: new Date(),
|
||||||
amount: 0,
|
amount: 0,
|
||||||
paidFor: [],
|
paidFor: [],
|
||||||
isReimbursement: false,
|
isReimbursement: false,
|
||||||
@@ -119,6 +122,32 @@ export function ExpenseForm({ group, expense, onSubmit, onDelete }: Props) {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="expenseDate"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem className="sm:order-1">
|
||||||
|
<FormLabel>Expense Date</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
className="date-base"
|
||||||
|
type="date"
|
||||||
|
value={(field.value ?? new Date())
|
||||||
|
.toISOString()
|
||||||
|
.substring(0, 10)}
|
||||||
|
onChange={(event) => {
|
||||||
|
return field.onChange(new Date(event.target.value))
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription>
|
||||||
|
Enter the date the expense was made.
|
||||||
|
</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="amount"
|
name="amount"
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export async function createExpense(
|
|||||||
data: {
|
data: {
|
||||||
id: randomId(),
|
id: randomId(),
|
||||||
groupId,
|
groupId,
|
||||||
|
expenseDate: expenseFormValues.expenseDate,
|
||||||
amount: expenseFormValues.amount,
|
amount: expenseFormValues.amount,
|
||||||
title: expenseFormValues.title,
|
title: expenseFormValues.title,
|
||||||
paidById: expenseFormValues.paidBy,
|
paidById: expenseFormValues.paidBy,
|
||||||
@@ -120,6 +121,7 @@ export async function updateExpense(
|
|||||||
return prisma.expense.update({
|
return prisma.expense.update({
|
||||||
where: { id: expenseId },
|
where: { id: expenseId },
|
||||||
data: {
|
data: {
|
||||||
|
expenseDate: expenseFormValues.expenseDate,
|
||||||
amount: expenseFormValues.amount,
|
amount: expenseFormValues.amount,
|
||||||
title: expenseFormValues.title,
|
title: expenseFormValues.title,
|
||||||
paidById: expenseFormValues.paidBy,
|
paidById: expenseFormValues.paidBy,
|
||||||
@@ -210,7 +212,7 @@ export async function getGroupExpenses(groupId: string) {
|
|||||||
return prisma.expense.findMany({
|
return prisma.expense.findMany({
|
||||||
where: { groupId },
|
where: { groupId },
|
||||||
include: { paidFor: { include: { participant: true } }, paidBy: true },
|
include: { paidFor: { include: { participant: true } }, paidBy: true },
|
||||||
orderBy: { createdAt: 'desc' },
|
orderBy: { expenseDate: 'desc' },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export type GroupFormValues = z.infer<typeof groupFormSchema>
|
|||||||
|
|
||||||
export const expenseFormSchema = z
|
export const expenseFormSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
expenseDate: z.coerce.date(),
|
||||||
title: z
|
title: z
|
||||||
.string({ required_error: 'Please enter a title.' })
|
.string({ required_error: 'Please enter a title.' })
|
||||||
.min(2, 'Enter at least two characters.'),
|
.min(2, 'Enter at least two characters.'),
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ async function main() {
|
|||||||
amount: Math.round(expenseRow.amount * 100),
|
amount: Math.round(expenseRow.amount * 100),
|
||||||
groupId: groupRow.id,
|
groupId: groupRow.id,
|
||||||
title: expenseRow.description,
|
title: expenseRow.description,
|
||||||
|
expenseDate: new Date(expenseRow.created_at.toDateString()),
|
||||||
createdAt: expenseRow.created_at,
|
createdAt: expenseRow.created_at,
|
||||||
isReimbursement: expenseRow.is_reimbursement === true,
|
isReimbursement: expenseRow.is_reimbursement === true,
|
||||||
paidById: participantIdsMapping[expenseRow.paid_by_participant_id],
|
paidById: participantIdsMapping[expenseRow.paid_by_participant_id],
|
||||||
|
|||||||
Reference in New Issue
Block a user