Skip to content

Commit

Permalink
Support creation of transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
range-of-motion committed Nov 9, 2024
1 parent 2716e46 commit 4d054c5
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 1 deletion.
60 changes: 59 additions & 1 deletion app/Http/Controllers/TransactionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@

use App\Models\Earning;
use App\Models\Spending;
use App\Models\Tag;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Inertia\Inertia;
use Inertia\Response;

class TransactionController extends Controller
{
public function index()
public function index(): Response
{
$space = Auth::user()->spaces()->first();

Expand All @@ -31,4 +34,59 @@ public function index()
],
);
}

public function create(): Response
{
$space = Auth::user()->spaces()->first();

$tags = Tag::query()
->where('space_id', $space->id)
->get();

return Inertia::render(
'Transaction/Create',
[
'tags' => $tags,
],
);
}

public function store(Request $request)
{
$request->validate([
'type' => ['required', 'in:earning,spending'],
'tag_id' => ['nullable', 'exists:tags,id'], // TODO: CHECK IF TAG BELONGS TO USER
'happened_on' => ['required', 'date', 'date_format:Y-m-d'],
'description' => ['required', 'max:255'],
'amount' => ['required', 'regex:/^\d*(\.\d{1,2})?$/'],
]);

$space = Auth::user()->spaces()->first();

if ($request->input('type') === 'earning') {
Earning::query()
->create([
'space_id' => $space->id,
'recurring_id' => null,
'happened_on' => $request->input('happened_on'),
'description' => $request->input('description'),
'amount' => (int) ($request->input('amount') * 100),
]);
}

if ($request->input('type') === 'spending') {
Spending::query()
->create([
'space_id' => $space->id,
'import_id' => null,
'recurring_id' => null,
'tag_id' => $request->input('tag_id'),
'happened_on' => $request->input('happened_on'),
'description' => $request->input('description'),
'amount' => (int) ($request->input('amount') * 100),
]);
}

return redirect()->route('transactions.index');
}
}
3 changes: 3 additions & 0 deletions resources/assets/js/Layout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ const user = computed(() => page.props.auth.user);
</Link>
</div>
<div class="flex space-x-5">
<Link class="flex items-center text-gray-500 hover:text-black" href="/transactions/create">
<svg class="h-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M8 12h8"/><path d="M12 8v8"/></svg>
</Link>
<Link class="flex items-center text-gray-500 hover:text-black" href="/log-out">
<svg class="h-3.5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" x2="9" y1="12" y2="12"/></svg>
</Link>
Expand Down
61 changes: 61 additions & 0 deletions resources/assets/js/Pages/Transaction/Create.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<script setup>
import { router } from '@inertiajs/vue3';
import { reactive } from 'vue';
defineProps({
tags: Array,
errors: Object,
});
const form = reactive({
type: 'earning',
tag_id: null,
happened_on: new Date().toISOString().split('T')[0],
description: null,
amount: null,
});
const create = () => {
router.post('/transactions', form);
};
</script>

<template>
<div class="my-10 mx-auto max-w-sm">
<div class="mb-5 font-bold text-xl">Create a transaction</div>
<div class="p-5 bg-white border border-gray-200 rounded-lg">
<div class="mb-5">
<div class="inline-flex overflow-hidden divide-x divide-gray-200 border border-gray-200 rounded-lg">
<button class="px-4 py-2 text-sm" :class="form.type === 'earning' ? 'bg-gray-100' : null" @click="form.type = 'earning'">Earning</button>
<button class="px-4 py-2 text-sm" :class="form.type === 'spending' ? 'bg-gray-100' : null" @click="form.type = 'spending'">Spending</button>
</div>
</div>
<div v-if="form.type === 'spending'" class="mb-5">
<label class="mb-2 block text-sm">Tag</label>
<select class="w-full px-3.5 py-2.5 text-sm border border-gray-200 rounded-lg appearance-none" v-model="form.tag_id">
<option :value="null">-</option>
<option v-for="tag in tags" :value="tag.id">{{ tag.name }}</option>
</select>
</div>
<div class="mb-5">
<label class="mb-2 block text-sm">Date</label>
<input class="w-full px-3.5 py-2.5 text-sm border border-gray-200 rounded-lg" v-model="form.happened_on" @keyup.enter="create" />
<div v-if="errors.happened_on" class="mt-2 text-sm text-red-500">{{ errors.happened_on }}</div>
</div>
<div class="mb-5">
<label class="mb-2 block text-sm">Description</label>
<input class="w-full px-3.5 py-2.5 text-sm border border-gray-200 rounded-lg" v-model="form.description" :placeholder="form.type === 'earning' ? 'Paycheck' : 'Groceries'" @keyup.enter="create" />
<div v-if="errors.description" class="mt-2 text-sm text-red-500">{{ errors.description }}</div>
</div>
<div class="mb-5">
<label class="mb-2 block text-sm">Amount</label>
<div class="relative">
<div class="absolute top-0 bottom-0 left-0 flex items-center pl-3.5 text-sm text-gray-400">€</div>
<input class="w-full pl-7 pr-3.5 py-2.5 text-sm border border-gray-200 rounded-lg" v-model="form.amount" placeholder="0.00" @keyup.enter="create" />
</div>
<div v-if="errors.amount" class="mt-2 text-sm text-red-500">{{ errors.amount }}</div>
</div>
<button class="px-4 py-3 leading-none font-medium text-sm text-white bg-gray-900 rounded-lg" @click="create">Create</button>
</div>
</div>
</template>
2 changes: 2 additions & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@
Route::get('/dashboard', DashboardController::class)->name('dashboard');

Route::get('/transactions', [TransactionController::class, 'index'])->name('transactions.index');
Route::get('/transactions/create', [TransactionController::class, 'create'])->name('transactions.create');
Route::post('/transactions', [TransactionController::class, 'store']);

0 comments on commit 4d054c5

Please sign in to comment.