category done

pull/1/head
Aji Kamaludin 3 years ago
parent 8a3fcadeb9
commit 42bad6da90
No known key found for this signature in database
GPG Key ID: 1DA43CE768971389

@ -0,0 +1,67 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Category;
class CategoryController extends Controller
{
public function index()
{
return inertia('Category', [
'categories' => Category::orderBy('created_at', 'desc')->paginate(5)
]);
}
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'description' => 'required|string|max:255',
'amount' => 'required|numeric|max:999999999|min:1'
]);
$category = Category::create([
'name' => $request->name,
'description' => $request->description,
'default_budget' => $request->amount
]);
$category->budgets()->create([
'budget' => $request->amount,
'start_date' => now()->toDateString(),
'end_date' => now()->endOfMonth()->toDateString(),
]);
return redirect()->route('categories');
}
public function update(Request $request, Category $category)
{
$request->validate([
'name' => 'required|string|max:255',
'description' => 'required|string|max:255',
'amount' => 'required|numeric|max:999999999|min:1'
]);
$category->update([
'name' => $request->name,
'description' => $request->description,
'default_budget' => $request->amount
]);
$budget = $category->budgets()->whereDate('end_date', now()->endOfMonth()->toDateString());
$budget->update(['budget' => $request->amount]);
return redirect()->route('categories');
}
public function destroy(Category $category)
{
$category->budgets()->delete();
$category->delete();
return redirect()->route('categories');
}
}

@ -10,4 +10,19 @@ class ExpenseController extends Controller
{
return inertia('Transaction');
}
public function store()
{
//
}
public function update()
{
//
}
public function destroy()
{
//
}
}

@ -15,4 +15,14 @@ class Category extends Model
'description',
'default_budget'
];
public function budgets()
{
return $this->hasMany(Budget::class);
}
public function transactions()
{
return $this->hasMany(Transaction::class);
}
}

@ -38,7 +38,7 @@ return [
'sqlite' => [
'driver' => 'sqlite',
'url' => env('DATABASE_URL'),
'database' => env('DB_DATABASE', database_path('database.sqlite')),
'database' => database_path('database.sqlite'),
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
],

@ -1 +1,2 @@
*.sqlite*
!database.sqlite

Binary file not shown.

18
package-lock.json generated

@ -2357,6 +2357,11 @@
"safe-buffer": "^5.0.1"
}
},
"classnames": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
},
"clean-css": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.2.tgz",
@ -2413,6 +2418,11 @@
"shallow-clone": "^3.0.0"
}
},
"clsx": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
"integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA=="
},
"collect.js": {
"version": "4.29.3",
"resolved": "https://registry.npmjs.org/collect.js/-/collect.js-4.29.3.tgz",
@ -5971,6 +5981,14 @@
"scheduler": "^0.20.2"
}
},
"react-toastify": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-8.1.0.tgz",
"integrity": "sha512-M+Q3rTmEw/53Csr7NsV/YnldJe4c7uERcY7Tma9mvLU98QT2VhIkKwjBzzxZkJRk/oBKyUAtkyMjMgO00hx6gQ==",
"requires": {
"clsx": "^1.1.1"
}
},
"read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",

@ -27,6 +27,8 @@
"tailwindcss": "^2.1.2"
},
"dependencies": {
"daisyui": "^1.16.4"
"classnames": "^2.3.1",
"daisyui": "^1.16.4",
"react-toastify": "^8.1.0"
}
}

417
public/css/app.css vendored

@ -1372,13 +1372,6 @@ html {
--tw-shadow: 0 0 0 1px var(--border-color) !important;
}
[data-theme=lofi] *:where(.badge) {
border-color: var(--border-color) !important;
--tw-border-opacity: 1 !important;
--tw-text-opacity: 1 !important;
--tw-shadow: 0 0 0 1px var(--border-color) !important;
}
[data-theme=lofi] *:where(.card) {
border-color: var(--border-color) !important;
--tw-border-opacity: 1 !important;
@ -1638,35 +1631,40 @@ html {
--tab-border: 1px;
--tab-radius: 0.5rem;
}
.avatar.placeholder>div {
.alert>:not([hidden])~:not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(0.5rem*(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(0.5rem*var(--tw-space-y-reverse));
}
.alert {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
justify-content: space-between;
--tw-bg-opacity: 1;
background-color: hsla(var(--b2)/var(--tw-bg-opacity,1));
padding: 1rem;
border-radius: var(--rounded-box,1rem);
}
.badge {
display: inline-flex;
@media (min-width:768px) {
.alert>:not([hidden])~:not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(0px*(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(0px*var(--tw-space-y-reverse));
}
.alert {
flex-direction: row;
}
}
.alert>* {
display: flex;
}
.avatar.placeholder>div {
display: flex;
align-items: center;
justify-content: center;
transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,transform;
transition-duration: .15s;
transition-duration: .2s;
transition-timing-function: cubic-bezier(.4,0,.2,1);
height: 1.25rem;
font-size: .875rem;
line-height: 1.25rem;
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
padding-left: .563rem;
padding-right: .563rem;
--tw-bg-opacity: 1;
background-color: hsla(var(--n)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--n)/var(--tw-border-opacity,1));
border-width: 1px;
--tw-text-opacity: 1;
color: hsla(var(--nc)/var(--tw-text-opacity,1));
border-radius: var(--rounded-badge,1.9rem);
}
.btn {
border-color: transparent;
@ -1935,12 +1933,6 @@ html {
--tw-text-opacity: 1;
color: hsla(var(--b2)/var(--tw-text-opacity,1));
}
.btn-outline .badge {
--tw-border-opacity: 1;
border-color: hsla(var(--nf)/var(--tw-border-opacity,1));
--tw-text-opacity: 1;
color: hsla(var(--nc)/var(--tw-text-opacity,1));
}
.btn-outline.btn-primary .badge {
--tw-bg-opacity: 1;
background-color: hsla(var(--p)/var(--tw-bg-opacity,1));
@ -1957,18 +1949,12 @@ html {
--tw-text-opacity: 1;
color: hsla(var(--sc)/var(--tw-text-opacity,1));
}
.btn-outline.btn-accent .badge {
--tw-bg-opacity: 1;
background-color: hsla(var(--a)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--a)/var(--tw-border-opacity,1));
--tw-text-opacity: 1;
color: hsla(var(--ac)/var(--tw-text-opacity,1));
}
.btn-outline .badge.outline {
.btn-outline.btn-primary .badge-outline {
background-color: transparent;
--tw-border-opacity: 1;
border-color: hsla(var(--nf)/var(--tw-border-opacity,1));
border-color: hsla(var(--p)/var(--tw-border-opacity,1));
--tw-text-opacity: 1;
color: hsla(var(--p)/var(--tw-text-opacity,1));
}
.btn-outline.btn-secondary .badge-outline {
background-color: transparent;
@ -1977,20 +1963,6 @@ html {
--tw-text-opacity: 1;
color: hsla(var(--s)/var(--tw-text-opacity,1));
}
.btn-outline:hover .badge {
--tw-bg-opacity: 1;
background-color: hsla(var(--b2)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--b2)/var(--tw-border-opacity,1));
--tw-text-opacity: 1;
color: hsla(var(--bc)/var(--tw-text-opacity,1));
}
.btn-outline:hover .badge.outline {
--tw-border-opacity: 1;
border-color: hsla(var(--b2)/var(--tw-border-opacity,1));
--tw-text-opacity: 1;
color: hsla(var(--nc)/var(--tw-text-opacity,1));
}
.btn-outline.btn-primary:hover .badge {
--tw-bg-opacity: 1;
background-color: hsla(var(--pc)/var(--tw-bg-opacity,1));
@ -2023,22 +1995,6 @@ html {
--tw-text-opacity: 1;
color: hsla(var(--sc)/var(--tw-text-opacity,1));
}
.btn-outline.btn-accent:hover .badge {
--tw-bg-opacity: 1;
background-color: hsla(var(--ac)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--ac)/var(--tw-border-opacity,1));
--tw-text-opacity: 1;
color: hsla(var(--a)/var(--tw-text-opacity,1));
}
.btn-outline.btn-accent:hover .badge.outline {
--tw-bg-opacity: 1;
background-color: hsla(var(--af)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--ac)/var(--tw-border-opacity,1));
--tw-text-opacity: 1;
color: hsla(var(--ac)/var(--tw-text-opacity,1));
}
.btn:active:focus,.btn:active:hover {
-webkit-animation: none;
animation: none;
@ -2053,6 +2009,23 @@ html {
.btn:focus-visible {
box-shadow: 0 0 0 2px hsl(var(--b1)),0 0 0 4px hsl(var(--nf));
}
.btn-primary {
--tw-bg-opacity: 1;
background-color: hsla(var(--p)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--p)/var(--tw-border-opacity,1));
--tw-text-opacity: 1;
color: hsla(var(--pc)/var(--tw-text-opacity,1));
}
.btn-primary.btn-active,.btn-primary:hover {
--tw-bg-opacity: 1;
background-color: hsla(var(--pf)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--pf)/var(--tw-border-opacity,1));
}
.btn-primary:focus-visible {
box-shadow: 0 0 0 2px hsl(var(--b1)),0 0 0 4px hsl(var(--p));
}
.btn-secondary {
--tw-bg-opacity: 1;
background-color: hsla(var(--s)/var(--tw-bg-opacity,1));
@ -2070,6 +2043,40 @@ html {
.btn-secondary:focus-visible {
box-shadow: 0 0 0 2px hsl(var(--b1)),0 0 0 4px hsl(var(--s));
}
.btn-warning {
--tw-bg-opacity: 1;
background-color: hsla(var(--wa)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--wa)/var(--tw-border-opacity,1));
--tw-text-opacity: 1;
color: hsla(var(--b2)/var(--tw-text-opacity,1));
}
.btn-warning.btn-active,.btn-warning:hover {
--tw-bg-opacity: 1;
background-color: hsla(var(--wa)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--wa)/var(--tw-border-opacity,1));
}
.btn-warning:focus-visible {
box-shadow: 0 0 0 2px hsl(var(--b1)),0 0 0 4px hsl(var(--wa));
}
.btn-error {
--tw-bg-opacity: 1;
background-color: hsla(var(--er)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--er)/var(--tw-border-opacity,1));
--tw-text-opacity: 1;
color: hsla(var(--b2)/var(--tw-text-opacity,1));
}
.btn-error.btn-active,.btn-error:hover {
--tw-bg-opacity: 1;
background-color: hsla(var(--er)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--er)/var(--tw-border-opacity,1));
}
.btn-error:focus-visible {
box-shadow: 0 0 0 2px hsl(var(--b1)),0 0 0 4px hsl(var(--er));
}
.btn.glass.btn-active,.btn.glass:hover {
--glass-opacity: 25%;
--glass-border-opacity: 15%;
@ -2077,6 +2084,18 @@ html {
.btn.glass:focus-visible {
box-shadow: 0 0 0 2px currentColor;
}
.btn-outline.btn-primary {
--tw-text-opacity: 1;
color: hsla(var(--p)/var(--tw-text-opacity,1));
}
.btn-outline.btn-primary:hover {
--tw-bg-opacity: 1;
background-color: hsla(var(--pf)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--pf)/var(--tw-border-opacity,1));
--tw-text-opacity: 1;
color: hsla(var(--pc)/var(--tw-text-opacity,1));
}
.btn-outline.btn-secondary {
--tw-text-opacity: 1;
color: hsla(var(--s)/var(--tw-text-opacity,1));
@ -2089,6 +2108,30 @@ html {
--tw-text-opacity: 1;
color: hsla(var(--sc)/var(--tw-text-opacity,1));
}
.btn-outline.btn-warning {
--tw-text-opacity: 1;
color: hsla(var(--wa)/var(--tw-text-opacity,1));
}
.btn-outline.btn-warning:hover {
--tw-bg-opacity: 1;
background-color: hsla(var(--wa)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--wa)/var(--tw-border-opacity,1));
--tw-text-opacity: 1;
color: hsla(var(--nc)/var(--tw-text-opacity,1));
}
.btn-outline.btn-error {
--tw-text-opacity: 1;
color: hsla(var(--er)/var(--tw-text-opacity,1));
}
.btn-outline.btn-error:hover {
--tw-bg-opacity: 1;
background-color: hsla(var(--er)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--er)/var(--tw-border-opacity,1));
--tw-text-opacity: 1;
color: hsla(var(--nc)/var(--tw-text-opacity,1));
}
.btn.loading.btn-circle:before,.btn.loading.btn-square:before {
margin-right: 0;
}
@ -2164,12 +2207,6 @@ html {
.card.compact .card-title {
margin-bottom: .25rem;
}
.card-title {
font-weight: 600;
font-size: 1.25rem;
line-height: 1.75rem;
margin-bottom: .75rem;
}
.card-actions:first-child {
margin-bottom: .5rem;
}
@ -2237,15 +2274,30 @@ html {
background-position-y: 0;
}
}
.drawer-toggle:focus-visible~.drawer-content .drawer-button.btn-primary {
box-shadow: 0 0 0 2px hsl(var(--b1)),0 0 0 4px hsl(var(--p));
}
.drawer-toggle:focus-visible~.drawer-content .drawer-button.btn-secondary {
box-shadow: 0 0 0 2px hsl(var(--b1)),0 0 0 4px hsl(var(--s));
}
.drawer-toggle:focus-visible~.drawer-content .drawer-button.btn-warning {
box-shadow: 0 0 0 2px hsl(var(--b1)),0 0 0 4px hsl(var(--wa));
}
.drawer-toggle:focus-visible~.drawer-content .drawer-button.btn-error {
box-shadow: 0 0 0 2px hsl(var(--b1)),0 0 0 4px hsl(var(--er));
}
.label-text {
font-size: .875rem;
line-height: 1.25rem;
--tw-text-opacity: 1;
color: hsla(var(--bc)/var(--tw-text-opacity,1));
}
.label-text-alt {
font-size: .75rem;
line-height: 1rem;
--tw-text-opacity: 1;
color: hsla(var(--bc)/var(--tw-text-opacity,1));
}
.label a:hover {
--tw-text-opacity: 1;
color: hsla(var(--bc)/var(--tw-text-opacity,1));
@ -2253,6 +2305,13 @@ html {
.input-bordered {
--tw-border-opacity: 0.2;
}
.input-error {
--tw-border-opacity: 1;
border-color: hsla(var(--er)/var(--tw-border-opacity,1));
}
.input-error:focus {
box-shadow: 0 0 0 2px hsl(var(--b1)),0 0 0 4px hsl(var(--er));
}
.input-disabled,.input[disabled] {
--tw-bg-opacity: 1;
background-color: hsla(var(--b2)/var(--tw-bg-opacity,1));
@ -2441,18 +2500,6 @@ html {
--tw-bg-opacity: 1;
background-color: hsla(var(--b2)/var(--tw-bg-opacity,1));
}
.badge-secondary {
--tw-bg-opacity: 1;
background-color: hsla(var(--s)/var(--tw-bg-opacity,1));
--tw-border-opacity: 1;
border-color: hsla(var(--s)/var(--tw-border-opacity,1));
--tw-text-opacity: 1;
color: hsla(var(--sc)/var(--tw-text-opacity,1));
}
.badge-outline.badge-secondary {
--tw-text-opacity: 1;
color: hsla(var(--s)/var(--tw-text-opacity,1));
}
.fixed {
position: fixed;
}
@ -2477,6 +2524,12 @@ html {
.left-0 {
left: 0px;
}
.top-10 {
top: 2.5rem;
}
.right-5 {
right: 1.25rem;
}
.z-0 {
z-index: 0;
}
@ -2490,9 +2543,9 @@ html {
margin-left: auto;
margin-right: auto;
}
.mx-2 {
margin-left: 0.5rem;
margin-right: 0.5rem;
.mx-1 {
margin-left: 0.25rem;
margin-right: 0.25rem;
}
.ml-3 {
margin-left: 0.75rem;
@ -2527,23 +2580,32 @@ html {
.-mt-px {
margin-top: -1px;
}
.mr-1 {
margin-right: 0.25rem;
}
.mb-1 {
margin-bottom: 0.25rem;
}
.mt-6 {
margin-top: 1.5rem;
}
.-mb-1 {
margin-bottom: -0.25rem;
}
.mb-4 {
margin-bottom: 1rem;
}
.mt-3 {
margin-top: 0.75rem;
}
.-mr-0\.5 {
margin-right: -0.125rem;
}
.-mr-0 {
margin-right: 0px;
}
.-mr-2 {
margin-right: -0.5rem;
}
.mt-6 {
margin-top: 1.5rem;
.mb-2 {
margin-bottom: 0.5rem;
}
.mr-3 {
margin-right: 0.75rem;
}
.mt-1 {
margin-top: 0.25rem;
@ -2578,9 +2640,6 @@ html {
.h-9 {
height: 2.25rem;
}
.h-4 {
height: 1rem;
}
.h-6 {
height: 1.5rem;
}
@ -2605,24 +2664,12 @@ html {
.w-full {
width: 100%;
}
.w-4 {
width: 1rem;
}
.w-6 {
width: 1.5rem;
}
.w-20 {
width: 5rem;
}
.w-1\/3 {
width: 33.333333%;
}
.w-2\/3 {
width: 66.666667%;
}
.min-w-full {
min-width: 100%;
}
.max-w-xl {
max-width: 36rem;
}
@ -2632,6 +2679,9 @@ html {
.max-w-7xl {
max-width: 80rem;
}
.max-w-xs {
max-width: 20rem;
}
.flex-1 {
flex: 1 1 0%;
}
@ -2660,6 +2710,16 @@ html {
.transform {
transform: var(--tw-transform);
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.animate-spin {
-webkit-animation: spin 1s linear infinite;
animation: spin 1s linear infinite;
}
.cursor-default {
cursor: default;
}
@ -2672,12 +2732,12 @@ html {
.grid-cols-1 {
grid-template-columns: repeat(1, minmax(0, 1fr));
}
.flex-row {
flex-direction: row;
}
.flex-col {
flex-direction: column;
}
.flex-wrap {
flex-wrap: wrap;
}
.items-start {
align-items: flex-start;
}
@ -2703,21 +2763,11 @@ html {
margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(0.25rem * var(--tw-space-y-reverse));
}
.space-x-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.5rem * var(--tw-space-x-reverse));
margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse)));
}
.space-y-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
}
.space-y-0 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(0px * var(--tw-space-y-reverse));
}
.overflow-hidden {
overflow: hidden;
}
@ -2730,6 +2780,9 @@ html {
.rounded {
border-radius: 0.25rem;
}
.rounded-full {
border-radius: 9999px;
}
.rounded-l-md {
border-top-left-radius: 0.375rem;
border-bottom-left-radius: 0.375rem;
@ -2756,6 +2809,9 @@ html {
.border-b {
border-bottom-width: 1px;
}
.border-solid {
border-style: solid;
}
.border-gray-300 {
--tw-border-opacity: 1;
border-color: rgba(209, 213, 219, var(--tw-border-opacity));
@ -2775,10 +2831,18 @@ html {
--tw-border-opacity: 1;
border-color: rgba(129, 140, 248, var(--tw-border-opacity));
}
.border-indigo-600 {
--tw-border-opacity: 1;
border-color: rgba(79, 70, 229, var(--tw-border-opacity));
}
.border-gray-100 {
--tw-border-opacity: 1;
border-color: rgba(243, 244, 246, var(--tw-border-opacity));
}
.border-green-700 {
--tw-border-opacity: 1;
border-color: rgba(4, 120, 87, var(--tw-border-opacity));
}
.bg-white {
--tw-bg-opacity: 1;
background-color: rgba(255, 255, 255, var(--tw-bg-opacity));
@ -2795,6 +2859,18 @@ html {
--tw-bg-opacity: 1;
background-color: rgba(238, 242, 255, var(--tw-bg-opacity));
}
.bg-green-500 {
--tw-bg-opacity: 1;
background-color: rgba(16, 185, 129, var(--tw-bg-opacity));
}
.bg-indigo-400 {
--tw-bg-opacity: 1;
background-color: rgba(129, 140, 248, var(--tw-bg-opacity));
}
.bg-indigo-600 {
--tw-bg-opacity: 1;
background-color: rgba(79, 70, 229, var(--tw-bg-opacity));
}
.fill-current {
fill: currentColor;
}
@ -2832,14 +2908,18 @@ html {
padding-left: 0.25rem;
padding-right: 0.25rem;
}
.px-3 {
padding-left: 0.75rem;
padding-right: 0.75rem;
.py-3 {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
}
.py-6 {
padding-top: 1.5rem;
padding-bottom: 1.5rem;
}
.px-3 {
padding-left: 0.75rem;
padding-right: 0.75rem;
}
.py-12 {
padding-top: 3rem;
padding-bottom: 3rem;
@ -2862,12 +2942,6 @@ html {
.pb-3 {
padding-bottom: 0.75rem;
}
.pt-4 {
padding-top: 1rem;
}
.pb-1 {
padding-bottom: 0.25rem;
}
.pt-6 {
padding-top: 1.5rem;
}
@ -2896,14 +2970,14 @@ html {
font-size: 1rem;
line-height: 1.5rem;
}
.text-xl {
font-size: 1.25rem;
line-height: 1.75rem;
}
.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
}
.text-xl {
font-size: 1.25rem;
line-height: 1.75rem;
}
.font-medium {
font-weight: 500;
}
@ -2922,9 +2996,6 @@ html {
.leading-7 {
line-height: 1.75rem;
}
.leading-4 {
line-height: 1rem;
}
.leading-tight {
line-height: 1.25;
}
@ -2985,6 +3056,10 @@ html {
--tw-text-opacity: 1;
color: rgba(31, 41, 55, var(--tw-text-opacity));
}
.text-green-500 {
--tw-text-opacity: 1;
color: rgba(16, 185, 129, var(--tw-text-opacity));
}
.text-green-600 {
--tw-text-opacity: 1;
color: rgba(5, 150, 105, var(--tw-text-opacity));
@ -3005,6 +3080,9 @@ html {
.opacity-100 {
opacity: 1;
}
.opacity-70 {
opacity: 0.7;
}
.shadow-sm {
--tw-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
@ -3070,10 +3148,18 @@ html {
--tw-bg-opacity: 1;
background-color: rgba(243, 244, 246, var(--tw-bg-opacity));
}
.hover\:bg-white:hover {
--tw-bg-opacity: 1;
background-color: rgba(255, 255, 255, var(--tw-bg-opacity));
}
.hover\:bg-gray-50:hover {
--tw-bg-opacity: 1;
background-color: rgba(249, 250, 251, var(--tw-bg-opacity));
}
.hover\:bg-indigo-400:hover {
--tw-bg-opacity: 1;
background-color: rgba(129, 140, 248, var(--tw-bg-opacity));
}
.hover\:text-gray-500:hover {
--tw-text-opacity: 1;
color: rgba(107, 114, 128, var(--tw-text-opacity));
@ -3125,6 +3211,10 @@ html {
--tw-text-opacity: 1;
color: rgba(55, 65, 81, var(--tw-text-opacity));
}
.focus\:text-indigo-700:focus {
--tw-text-opacity: 1;
color: rgba(67, 56, 202, var(--tw-text-opacity));
}
.focus\:text-indigo-800:focus {
--tw-text-opacity: 1;
color: rgba(55, 48, 163, var(--tw-text-opacity));
@ -3180,10 +3270,6 @@ html {
margin-left: 2.5rem;
}
.sm\:ml-6 {
margin-left: 1.5rem;
}
.sm\:block {
display: block;
}
@ -3200,10 +3286,6 @@ html {
height: 5rem;
}
.sm\:min-w-full {
min-width: 100%;
}
.sm\:max-w-md {
max-width: 28rem;
}
@ -3255,18 +3337,10 @@ html {
width: 33.333333%;
}
.md\:w-3\/4 {
width: 75%;
}
.md\:w-2\/3 {
width: 66.666667%;
}
.md\:flex-1 {
flex: 1 1 0%;
}
.md\:grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
@ -3275,12 +3349,6 @@ html {
flex-direction: row;
}
.md\:space-x-0 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0px * var(--tw-space-x-reverse));
margin-left: calc(0px * calc(1 - var(--tw-space-x-reverse)));
}
.md\:space-y-0 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse)));
@ -3295,11 +3363,6 @@ html {
border-left-width: 1px;
}
.md\:px-8 {
padding-left: 2rem;
padding-right: 2rem;
}
.md\:pl-8 {
padding-left: 2rem;
}

3803
public/js/app.js vendored

File diff suppressed because one or more lines are too long

@ -0,0 +1,52 @@
import { Link } from '@inertiajs/inertia-react';
import classNames from 'classnames';
const PageLink = ({ active, label, url }) => {
const className = classNames(
[
'mr-1 mb-1',
'px-4 py-3',
'border border-solid border-gray-300 rounded',
'text-sm',
'bg-white',
'hover:bg-white',
'focus:outline-none focus:border-indigo-700 focus:text-indigo-700'
],
{
'border-indigo-600 bg-indigo-600 text-white hover:bg-indigo-400': active
}
);
return (
<Link className={className} href={url}>
<span dangerouslySetInnerHTML={{ __html: label }}></span>
</Link>
);
};
// Previous, if on first page
// Next, if on last page
// and dots, if exists (...)
const PageInactive = ({ label }) => {
const className = classNames(
'mr-1 mb-1 px-4 py-3 text-sm border rounded border-solid border-gray-300 text-gray'
);
return (
<div className={className} dangerouslySetInnerHTML={{ __html: label }} />
);
};
export default ({ links = [] }) => {
// dont render, if there's only 1 page (previous, 1, next)
if (links.length === 3) return null;
return (
<div className="flex flex-wrap mt-6 -mb-1">
{links.map(({ active, label, url }) => {
return url === null ? (
<PageInactive key={label} label={label} />
) : (
<PageLink key={label} label={label} active={active} url={url} />
);
})}
</div>
);
};

@ -1,6 +1,5 @@
import React, { useState } from 'react';
import ApplicationLogo from '@/Components/ApplicationLogo';
import Dropdown from '@/Components/Dropdown';
import { ToastContainer } from 'react-toastify';
import NavLink from '@/Components/NavLink';
import ResponsiveNavLink from '@/Components/ResponsiveNavLink';
import { Link } from '@inertiajs/inertia-react';
@ -22,13 +21,13 @@ export default function Authenticated({ header, children }) {
</div>
<div className="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
<NavLink href={route('dashboard')} active={route().current('transactions')}>
<NavLink href={route('transactions')} active={route().current('transactions')}>
Transaction
</NavLink>
<NavLink href={route('dashboard')} active={route().current('dashboard')}>
<NavLink href={route('categories')} active={route().current('categories')}>
Category
</NavLink>
<NavLink href={route('dashboard')} active={route().current('dashboard')}>
<NavLink href={route('summary')} active={route().current('summary')}>
Summary
</NavLink>
</div>
@ -62,13 +61,13 @@ export default function Authenticated({ header, children }) {
<div className={(showingNavigationDropdown ? 'block' : 'hidden') + ' sm:hidden'}>
<div className="pt-2 pb-3 space-y-1">
<ResponsiveNavLink href={route('dashboard')} active={route().current('transactions')}>
<ResponsiveNavLink href={route('transactions')} active={route().current('transactions')}>
Transaction
</ResponsiveNavLink>
<ResponsiveNavLink href={route('dashboard')} active={route().current('dashboard')}>
<ResponsiveNavLink href={route('transactions')} active={route().current('transactions')}>
Category
</ResponsiveNavLink>
<ResponsiveNavLink href={route('dashboard')} active={route().current('dashboard')}>
<ResponsiveNavLink href={route('summary')} active={route().current('summary')}>
Summary
</ResponsiveNavLink>
</div>
@ -82,6 +81,18 @@ export default function Authenticated({ header, children }) {
)}
<main>{children}</main>
<ToastContainer
position="top-right"
autoClose={5000}
theme='colored'
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
/>
</div>
);
}

@ -0,0 +1,180 @@
import React, { useState } from 'react';
import Pagination from '@/Components/Pagination'
import Authenticated from '@/Layouts/Authenticated';
import { toast } from 'react-toastify';
import { Head, useForm } from '@inertiajs/inertia-react';
export default function Category(props) {
const [category, setCategory] = useState(null)
const { data: categories , links } = props.categories
const { data, setData, errors, post, put, processing, delete: destroy } = useForm({
name: '',
description: '',
amount: 0
})
const handleChange = (e) => {
const key = e.target.id;
const value = e.target.value
setData(key, value)
}
const handleReset = () => {
setCategory(null)
setData({
name: '',
description: '',
amount: ''
})
}
const handleEdit = (category) => {
setCategory(category)
setData({
name: category.name,
description: category.description,
amount: category.default_budget
})
}
const handleDelete = (category) => {
destroy(route('categories.destroy', category), {
onBefore: () => confirm('Are you sure you want to delete this record?'),
onSuccess: () => Promise.all([
handleReset(),
toast.success('data has been deleted')
])
})
}
const handleSubmit = (e) => {
e.preventDefault()
if(category !== null) {
put(route('categories.update', category), {
onSuccess: () => Promise.all([
handleReset(),
toast.success('The Data has been changed')
])
})
return
}
post(route('categories.store'), {
onSuccess: () => Promise.all([
handleReset(),
toast.success('Data has been saved')
])
})
}
return (
<Authenticated
errors={props.errors}
header={<h2 className="font-semibold text-xl text-gray-800 leading-tight">Category</h2>}
>
<Head title="Category" />
<div className="flex flex-col space-y-2 md:space-y-0 md:flex-row py-12">
<div className="w-full md:w-1/3 px-6 md:pl-8">
<div className="card bg-white">
<div className="card-body">
<div className="form-control">
<label className="label">
<span className="label-text">Name</span>
</label>
<input
type="text"
placeholder="Name"
className={`input input-bordered ${errors.name ? 'input-error' : ''}`}
id="name"
value={data.name}
onChange={handleChange}
/>
<label className="label">
<span className="label-text-alt">
{errors.name}
</span>
</label>
</div>
<div className="form-control">
<label className="label">
<span className="label-text">Description</span>
</label>
<input
type="text"
placeholder="Description"
className={`input input-bordered ${errors.description ? 'input-error' : ''}`}
id="description"
value={data.description}
onChange={handleChange}
/>
<label className="label">
<span className="label-text-alt">
{errors.description}
</span>
</label>
</div>
<div className="form-control">
<label className="label">
<span className="label-text">Amount</span>
</label>
<input
type="number"
placeholder="Amount"
className={`input input-bordered ${errors.amount ? 'input-error' : ''}`}
id="amount"
value={data.amount}
onChange={handleChange}
/>
<label className="label">
<span className="label-text-alt">
{errors.amount}
</span>
</label>
</div>
<div className="card-actions">
<button className={`btn btn-primary ${processing && 'animate-spin'}`} onClick={handleSubmit} disabled={processing}>Add</button>
<button className="btn btn-secondary" onClick={handleReset} disabled={processing}>Clear</button>
</div>
</div>
</div>
</div>
<div className="w-full md:w-2/3 px-6 md:pr-8">
<div className="card bg-white">
<div className="card-body">
<div className="overflow-x-auto">
<table className="table w-full table-zebra">
<thead>
<tr>
<th></th>
<th>Name</th>
<th>Description</th>
<th>Amount</th>
<th></th>
</tr>
</thead>
<tbody className={processing ? "opacity-70" : ""}>
{categories?.map(category => (
<tr key={category.id}>
<th>{category.id}</th>
<td>{category.name}</td>
<td>{category.description}</td>
<td>{category.default_budget}</td>
<td>
<div className="btn btn-warning mx-1" onClick={() => handleEdit(category)}>Edit</div>
<div className="btn btn-error mx-1" onClick={() => handleDelete(category)}>Delete</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
<Pagination links={links} />
</div>
</div>
</div>
</div>
</Authenticated>
);
}

@ -1,22 +0,0 @@
import React from 'react';
import Authenticated from '@/Layouts/Authenticated';
import { Head } from '@inertiajs/inertia-react';
export default function Dashboard(props) {
return (
<Authenticated
errors={props.errors}
header={<h2 className="font-semibold text-xl text-gray-800 leading-tight">Dashboard</h2>}
>
<Head title="Dashboard" />
<div className="py-12">
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div className="p-6 bg-white border-b border-gray-200">You're logged in!</div>
</div>
</div>
</div>
</Authenticated>
);
}

@ -30,8 +30,8 @@ export default function Transaction(props) {
<div className="w-full md:w-2/3 px-6 md:pr-8">
<div className="card bg-white">
<div className="card-body">
<div class="overflow-x-auto">
<table class="table w-full table-zebra">
<div className="overflow-x-auto">
<table className="table w-full table-zebra">
<thead>
<tr>
<th></th>

@ -4,6 +4,7 @@ import React from 'react';
import { render } from 'react-dom';
import { createInertiaApp } from '@inertiajs/inertia-react';
import { InertiaProgress } from '@inertiajs/progress';
import 'react-toastify/dist/ReactToastify.css';
const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';

@ -4,6 +4,7 @@ use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use App\Http\Controllers\ExpenseController;
use App\Http\Controllers\CategoryController;
/*
|--------------------------------------------------------------------------
@ -17,8 +18,17 @@ use App\Http\Controllers\ExpenseController;
*/
Route::get('/', [ExpenseController::class, 'index'])->name('transactions');
Route::get('/das', function () {
})->name('dashboard');
Route::post('/transactions', [ExpenseController::class, 'store'])->name('transactions.store');
Route::put('/transactions/{transaction}', [ExpenseController::class, 'update'])->name('transactions.update');
Route::delete('/transactions/{transaction}', [ExpenseController::class, 'destroy'])->name('transactions.destroy');
Route::get('/categories', [CategoryController::class, 'index'])->name('categories');
Route::post('/categories', [CategoryController::class, 'store'])->name('categories.store');
Route::put('/categories/{category}', [CategoryController::class, 'update'])->name('categories.update');
Route::delete('/categories/{category}', [CategoryController::class, 'destroy'])->name('categories.destroy');
Route::get('/summary', function () {
})->name('summary');
// Route::get('/dashboard', function () {
// return Inertia::render('Dashboard');

Loading…
Cancel
Save